2012-11-05 19 views
27

Chciałbym wiedzieć, co dokładnie nazwę metoda jest eliksir:Jak wywołać metodę dynamicznie w eliksirie, podając nazwę modułu i metody?

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 

Ale mogę zrobić prawie to samo w Erlang:

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

Jak mogę to zrobić w eliksir?

Odpowiedz

39

Możesz użyć apply/3, który jest tylko opakowaniem o numerze :erlang.apply/3. Po prostu invokes the given function from the module with an array of arguments. Ponieważ podajesz argumenty jako nazwy modułów i funkcji, możesz używać zmiennych.

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

Jeśli chcesz zrozumieć więcej o tym, jak eliksir obsługuje wywołania funkcji (i wszystko inne) należy spojrzeć na quote i unquote.

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

który zwraca homoiczną reprezentację wywołania funkcji.

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

Można unquote cytowany wywołanie funkcji z Code.eval_quoted/3

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

EDIT: tutaj jest przykład przy użyciu Enum.fetch wraz z odm.

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

Dobrze. Tak więc nazwa metody jest atomem. Teraz myślę, że to tylko składnia, która nie pozwala nam pisać 'module.method' w eliksiru, prawda? – halfelf

+1

Wierzę, że masz rację. Myślę, że jedynym sposobem na wykonanie tej pracy byłoby zmiana składni, aby używać atomów podczas wywoływania funkcji modułu (tj. ': List.: Nth'). Wolałbym po prostu użyć zastosować w takich przypadkach. – lastcanal

+0

Dzięki. Ta odpowiedź jest bardzo pomocna. – halfelf