Dynamic Elixir-按字符串名称对模块调用方法
一般来说,我对长生不老药和函数式编程语言是相当陌生的 在Elixir中,我想调用模块上的一个特定函数,给定模块名为字符串 我有以下(非常糟糕的)代码正在工作,这基本上符合我的要求:Dynamic Elixir-按字符串名称对模块调用方法,dynamic,module,load,elixir,Dynamic,Module,Load,Elixir,一般来说,我对长生不老药和函数式编程语言是相当陌生的 在Elixir中,我想调用模块上的一个特定函数,给定模块名为字符串 我有以下(非常糟糕的)代码正在工作,这基本上符合我的要求: module_name = elem(elem(Code.eval_file("module.ex", __DIR__), 0), 1) apply(module_name, :helloWorld, []) 这(至少据我所知)编译了当前目录中module.ex的(已编译)模块。我正在从两个元组中提取模块名称(不是
module_name = elem(elem(Code.eval_file("module.ex", __DIR__), 0), 1)
apply(module_name, :helloWorld, [])
这(至少据我所知)编译了当前目录中module.ex
的(已编译)模块。我正在从两个元组中提取模块名称(不是字符串,不知道它实际上是什么数据类型),并在其上运行方法helloWorld
此代码有两个问题:
defmodule T do
def first([]), do: nil
def first([h|t]), do: h
end
module.ex
。但由于module.ex已经编译和加载,它不希望发生这种情况Book.helloWorld
谢谢。好吧,这就是寻求帮助的地方:你一开口就会自己想出来的
现在只需使用
apply(String.to_现有的\u原子(“Elixir.Module”),:helloWorld,[])
。(可能名称“Module”是不允许的,我不知道)还请注意,模块的名称是一个atom,因此使用字符串。通常不需要使用现有的\u atom
。考虑这个代码:
defmodule T do
def first([]), do: nil
def first([h|t]), do: h
end
在这种情况下,您只需以以下方式执行应用:
apply(T,:first,[[1,2,3]])
#=> 1
或者这个例子(下面的列表是长生不老药模块):
我的意思是,如果您知道模块的名称,就不必将其作为字符串传递,然后将该字符串转换为现有的atom。只需使用不带引号的名称 请注意,您始终需要在模块前面加上“Elixir” 打印“测试”
并返回{:ok}以下是一个简单的解释: 假设您有这样一个模块:
defmodule MyNamespace.Printer do
def print_hello(name) do
IO.puts("Hello, #{name}!")
end
end
module_name = "Elixir.MyNamespace.Printer"
module = String.to_existing_atom(module_name)
module.print_hello("John")
a_module_name = :"Elixir.MyNamespace.Printer"
a_function_name = :print_hello
apply(a_module_name, a_function_name, ["Jackie"])
然后,您有一个字符串,其中包含可以在应用程序中传递的模块名称,如下所示:
defmodule MyNamespace.Printer do
def print_hello(name) do
IO.puts("Hello, #{name}!")
end
end
module_name = "Elixir.MyNamespace.Printer"
module = String.to_existing_atom(module_name)
module.print_hello("John")
a_module_name = :"Elixir.MyNamespace.Printer"
a_function_name = :print_hello
apply(a_module_name, a_function_name, ["Jackie"])
每当您收到字符串module_name时,您都可以实例化一个模块并调用模块上的函数,如下所示:
defmodule MyNamespace.Printer do
def print_hello(name) do
IO.puts("Hello, #{name}!")
end
end
module_name = "Elixir.MyNamespace.Printer"
module = String.to_existing_atom(module_name)
module.print_hello("John")
a_module_name = :"Elixir.MyNamespace.Printer"
a_function_name = :print_hello
apply(a_module_name, a_function_name, ["Jackie"])
它将打印:
Hello, John!
Hello, Jane!
动态调用函数MyNamespace.Printer.print_hello/1的另一种方法是:
print_hello_func = &module.print_hello/1
print_hello_func.("Jane")
它将打印:
Hello, John!
Hello, Jane!
或者,如果您希望将模块名和函数名都设置为atom,并将它们传递到某个地方执行,您可以编写如下代码:
defmodule MyNamespace.Printer do
def print_hello(name) do
IO.puts("Hello, #{name}!")
end
end
module_name = "Elixir.MyNamespace.Printer"
module = String.to_existing_atom(module_name)
module.print_hello("John")
a_module_name = :"Elixir.MyNamespace.Printer"
a_function_name = :print_hello
apply(a_module_name, a_function_name, ["Jackie"])
然后,无论何时,只要有一个_模块_名称和一个_函数_名称作为原子,就可以这样调用:
defmodule MyNamespace.Printer do
def print_hello(name) do
IO.puts("Hello, #{name}!")
end
end
module_name = "Elixir.MyNamespace.Printer"
module = String.to_existing_atom(module_name)
module.print_hello("John")
a_module_name = :"Elixir.MyNamespace.Printer"
a_function_name = :print_hello
apply(a_module_name, a_function_name, ["Jackie"])
它会打印出来
Hello, Jackie!
当然,您可以将模块名称和函数名称作为字符串传递,然后将它们转换为原子。或者,您可以将模块名作为atom传递,并将函数作为对函数的引用。小注:您应该尽可能使用现有的atom。原子不是垃圾!谢谢我不知道原子不是垃圾收集的。将编辑我的答案。更多的理由使用<代码>字符串。toySuthItgIngObjult:<代码> String。toAxObjs/COD> >公开攻击向量。有关详细信息,请参见,这是完全正确的。但在我的例子中,目标是使模块名动态化。当然,如果您知道模块的名称,也可以这样做。