web-dev-qa-db-ja.com

モジュール名とメソッド名の両方を指定して、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's an atom

しかし、erlangでもほぼ同じことができます。

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

エリキシルでこれを行うにはどうすればよいですか?

35
halfelf

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]]}

引用符で囲まれた関数呼び出しは、 Code.eval_quoted/3unquoteできます。

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

編集:varとともにEnum.fetchを使用する例を次に示します。

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