Elixir - 通过String-name调用模块上的方法

lsc*_*ann 10 load module dynamic elixir

我对Elixir和一般的函数式编程语言都很陌生.

在Elixir中,我想在Module上调用一个特定的函数,模块名称为String.

我有以下(非常糟糕的)代码工作,这几乎是我想要的:

module_name = elem(elem(Code.eval_file("module.ex", __DIR__), 0), 1)
apply(module_name, :helloWorld, [])
Run Code Online (Sandbox Code Playgroud)

这(至少据我所知)编译module.ex当前目录中的(已编译的)模块.我正在从两个元组中提取模块名称(不是字符串,不知道它实际上是什么数据类型)并在其helloWorld上运行方法.

这段代码有两个问题:

  1. 它打印出类似的警告redefining module Balance.我当然不希望在生产中发生这种情况.

  2. AFAIK此代码编译module.ex.但是由于module.ex已经被编译和加载,所以它不希望发生这种情况.

我不需要通过文件名调用这些模块上的方法,模块名也可以.但它必须通过动态,例如.在检查模块是否存在后,在命令行输入"Book"应该调用该函数Book.helloWorld.

谢谢.

lsc*_*ann 15

好吧,那就是请求帮助:你会在你问的那一刻自己弄明白.;)

apply(String.to_existing_atom("Elixir.Module"), :helloWorld, [])现在就用 (也许不允许使用"模块"这个名称,不知道)

  • 小注意:尽可能使用to_existing_atom.原子不是垃圾收集! (2认同)

Jas*_*onG 8

请注意,您始终需要在模块前添加"Elixir".

defmodule Test do
  def test(text) do
    IO.puts("#{text}")
  end
end

apply(String.to_existing_atom("Elixir.Test"), :test, ["test"])
Run Code Online (Sandbox Code Playgroud)

打印"test"并返回{:ok}


Châ*_*ĩnh 5

这是一个简单的解释:

假设你有一个这样的模块:

defmodule MyNamespace.Printer do
  def print_hello(name) do
    IO.puts("Hello, #{name}!")
  end
end
Run Code Online (Sandbox Code Playgroud)

然后你有一个包含模块名称的字符串,你可以像这样在你的应用程序中传递它:

module_name = "Elixir.MyNamespace.Printer"
Run Code Online (Sandbox Code Playgroud)

每当您收到字符串module_name 时,您就可以实例化一个模块并调用该模块上的函数,如下所示:

module = String.to_existing_atom(module_name)
module.print_hello("John")
Run Code Online (Sandbox Code Playgroud)

它会打印:

Hello, John!
Run Code Online (Sandbox Code Playgroud)

动态调用函数 MyNamespace.Printer.print_hello/1 的另一种方法是:

print_hello_func = &module.print_hello/1
print_hello_func.("Jane")
Run Code Online (Sandbox Code Playgroud)

它会打印:

Hello, Jane!
Run Code Online (Sandbox Code Playgroud)

或者,如果您想同时将 module_name 作为 atom 和 function_name 作为 atom,并将它们传递到某个地方执行,您可以这样写:

a_module_name = :"Elixir.MyNamespace.Printer"
a_function_name = :print_hello
Run Code Online (Sandbox Code Playgroud)

然后每当你有 a_module_name 和 a_function_name 作为原子时,你可以这样调用:

apply(a_module_name, a_function_name, ["Jackie"])
Run Code Online (Sandbox Code Playgroud)

它会打印

Hello, Jackie!
Run Code Online (Sandbox Code Playgroud)

当然,您可以将 module_name 和 function_name 作为字符串传递,稍后将它们转换为原子。或者您可以将模块名称作为原子传递,并将函数作为对函数的引用。