我对Elixir和一般的函数式编程语言都很陌生。
在Elixir中,我想在Module上调用一个特定的函数,模块名称为String。
我有以下(非常糟糕的)代码正常工作,这几乎是我想要的:
toString
这(至少据我所知)编译当前目录中module_name = elem(elem(Code.eval_file("module.ex", __DIR__), 0), 1)
apply(module_name, :helloWorld, [])
的(已编译的)模块。我正在从两个元组中提取模块名称(不是字符串,不知道它实际上是什么数据类型)并在其上运行方法module.ex
。
此代码存在两个问题:
它会输出helloWorld
之类的警告。我当然不希望这种情况发生在制作中。
AFAIK此代码编译redefining module Balance
。但是由于module.ex已经被编译和加载,因此不希望发生这种情况。
我不需要通过文件名调用这些模块上的方法,模块名也可以。但它必须通过动态,例如。在检查模块是否存在后,在命令行输入“Book”应该调用函数module.ex
。
感谢。
答案 0 :(得分:12)
嗯,那就是请求帮助:你会在你问的那一刻自己弄明白。 ;)
现在就使用request
。 (也许不允许使用名称“模块”,不知道)
答案 1 :(得分:8)
请注意,您始终需要在模块前加上" Elixir。"
defmodule Test do
def test(text) do
IO.puts("#{text}")
end
end
apply(String.to_existing_atom("Elixir.Test"), :test, ["test"])
打印"测试" 并返回{:ok}
答案 2 :(得分:4)
另请注意,模块的名称是一个原子,因此通常不需要String.to_existing_atom
。请考虑以下代码:
defmodule T do
def first([]), do: nil
def first([h|t]), do: h
end
在这种情况下,您只需以这种方式执行申请:
apply(T,:first,[[1,2,3]])
#=> 1
或者这个例子(下面的列表是Elixir List模块):
apply(List,:first,[[1,2,3]])
#=> 1
我的意思是说,如果您知道模块的名称,则不必将其作为字符串传递,然后将字符串转换为现有原子。只需使用不带引号的名称。
答案 3 :(得分:3)
这里是一个简单的解释:
假设您有一个像这样的模块:
defmodule MyNamespace.Printer do
def print_hello(name) do
IO.puts("Hello, #{name}!")
end
end
然后您将拥有一个字符串,其中包含可以在应用程序中像这样传递的模块名称:
module_name = "Elixir.MyNamespace.Printer"
每当收到字符串 module_name 时,您都可以实例化模块并在模块上调用函数,如下所示:
module = String.to_existing_atom(module_name)
module.print_hello("John")
它将打印:
Hello, John!
动态调用函数MyNamespace.Printer.print_hello / 1的另一种方法是:
print_hello_func = &module.print_hello/1
print_hello_func.("Jane")
它将打印:
Hello, Jane!
或者,如果您想同时将module_name作为原子和function_name作为原子,并将它们传递给在某个地方执行,则可以编写如下代码:
a_module_name = :"Elixir.MyNamespace.Printer"
a_function_name = :print_hello
然后,只要您将a_module_name和a_function_name作为原子,就可以这样调用:
apply(a_module_name, a_function_name, ["Jackie"])
它将打印
Hello, Jackie!
当然,您可以将module_name和function_name传递为字符串,然后将它们转换为原子。或者,您可以将模块名称作为原子传递,并将函数作为对函数的引用。