【问题标题】:How to call a method dynamically in Elixir, by specifying both module and method name?如何通过指定模块和方法名称在 Elixir 中动态调用方法?
【发布时间】:2012-10-25 05:18:49
【问题描述】:

我想知道 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

如何在 elixir 中做到这一点?

【问题讨论】:

    标签: erlang metaprogramming elixir


    【解决方案1】:

    您可以使用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])
    

    如果您想了解更多关于 elixir 如何处理函数调用(以及其他所有内容)的信息,您应该查看 quoteunquote

    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)
    

    编辑:这是一个使用 Enum.fetch 和 var 的示例。

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

    【讨论】:

    • 好。所以方法名是一个原子。现在我认为这只是不允许我们在 elixir 中写 module.method 的语法,对吧?
    • 我相信你是对的。我认为完成这项工作的唯一方法是在调用模块函数时更改语法以使用原子(即:lists.:nth)。我宁愿只在这种情况下使用 apply。
    • 谢谢。这个答案很有帮助。
    • 您能否展示如何为普通的长生不老药功能做到这一点。像Enum.fetch 这样的东西?有变量变量还是变量函数?
    • quoted_fetch = quote do: Enum.fetch([1,2,3], var!(item)); {value, binding} = Code.eval_quoted(quoted_fetch, [item: 2])
    猜你喜欢
    • 2016-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-06
    • 2017-10-10
    • 1970-01-01
    • 2013-10-04
    • 1970-01-01
    相关资源
    最近更新 更多