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

时间:2016-04-17 16:50:55

标签: dynamic module load elixir

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

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

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

toString

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

此代码存在两个问题:

  1. 它会输出helloWorld之类的警告。我当然不希望这种情况发生在制作中。

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

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

    感谢。

4 个答案:

答案 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传递为字符串,然后将它们转换为原子。或者,您可以将模块名称作为原子传递,并将函数作为对函数的引用。