Dynamic 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的(已编译)模块。我正在从两个元组中提取模块名称(不是

一般来说,我对长生不老药和函数式编程语言是相当陌生的

在Elixir中,我想调用模块上的一个特定函数,给定模块名为字符串

我有以下(非常糟糕的)代码正在工作,这基本上符合我的要求:

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
  • 它会打印一条警告,如重新定义模块平衡。我当然不希望这种情况在生产中发生

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

  • 我不需要通过文件名调用这些模块上的方法,模块名也可以。但是它必须是动态的,例如,在命令行中输入“Book”应该在检查模块是否存在后调用函数
    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> >公开攻击向量。有关详细信息,请参见,这是完全正确的。但在我的例子中,目标是使模块名动态化。当然,如果您知道模块的名称,也可以这样做。