Подтвердить что ты не робот

Как динамически вызвать метод в Elixir, указав имя модуля и метода?

Я хотел бы знать, что именно имя метода находится в elixir:

array = [1,2,3]
module_name = :lists
method_name = :nth                  # this not working
module_name.method_name(1, array)   # error, undef function lists.method_name/2
module_name.nth(1, array)           # returns 1, module_name is OK. It an atom

Но я могу сделать почти то же самое в erlang:

A = [1,2,3].
X = lists.
Y = nth.
X:Y(1,A).  #  returns 1

Как это сделать в эликсире?

4b9b3361

Ответ 1

Вы можете использовать apply/3, который является всего лишь оберткой вокруг :erlang.apply/3. Это просто вызывает данный function из module с массивом arguments. Поскольку вы передаете аргументы как модуль и функцию имена, вы можете использовать переменные.

apply(:lists, :nth, [1, [1,2,3]])
apply(module_name, method_name, [1, array])

Если вы хотите больше узнать о том, как elixir обрабатывает вызовы функций (и все остальное), вы должны взглянуть на quote и unquote.

contents = quote do: unquote(module_name).unquote(method_name)(1, unquote(array))

который возвращает гомоциконное представление вызова функции.

{{:.,0,[:lists,:nth]},0,[1,[1,2,3]]}

Вы можете unquote вызвать цитируемый вызов функции Code.eval_quoted/3

{value, binding} = Code.eval_quoted(contents)

Изменить: вот пример использования Enum.fetch вместе с var.

quoted_fetch = quote do: Enum.fetch([1,2,3], var!(item));             
{value, binding} = Code.eval_quoted(quoted_fetch, [item: 2])