2012-11-05 25 views
27

我想知道確切的方法名是什麼仙丹:如何通過指定模塊和方法名稱在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 

但我幾乎可以做同樣的事情在二郎:

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

我怎樣才能做到這一點的靈藥?

回答

39

您可以使用apply/3這僅僅是圍繞:erlang.apply/3的包裝。它只是invokes the given function from the module with an array of arguments.由於您將參數作爲模塊和函數名稱傳遞,因此可以使用變量。

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

如果您想了解更多關於靈藥如何處理函數調用(和其他一切),你應該看一看quoteunquote

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

它返回函數調用的homoiconic表示形式。

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

您可以Code.eval_quoted/3

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

編輯unquote引用的函數調用:這裏是使用Enum.fetch用VAR一起的例子。

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

好。所以方法名稱是一個原子。現在我認爲這只是不允許我們在elixir中編寫'module.method'的語法,對吧? – halfelf

+1

我相信你是對的。我認爲做這個工作的唯一方法是在調用模塊函數時改變使用原子的語法(即':lists。:nth')。我寧願在這種情況下使用apply。 – lastcanal

+0

謝謝。這個答案是非常有幫助的。 – halfelf

相關問題