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

loading...


7

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

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

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

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

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

这段代码有两个问题:

  • 它会输出类似 redefining module Balance 的警告 . 我当然不希望在 生产环境 中发生这种情况 .

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

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

谢谢 .

3回答

  • 7

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

    现在只使用 apply(String.to_existing_atom("Elixir.Module"), :helloWorld, []) . (也许名字"Module"不是't allowed, don't知道)


  • 2

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

    defmodule Test do
      def test(text) do
        IO.puts("#{text}")
      end
    end
    
    apply(String.to_existing_atom("Elixir.Test"), :test, ["test"])
    

    打印“test”并返回{:ok}


  • 10

    另请注意,模块的名称是一个原子,因此通常不需要 String.to_existing_atom . 考虑以下代码:

    defmodule T do
      def first([]), do: nil
      def first([h|t]), do: h
    end
    

    在这种情况下,您只需以这种方式执行apply:

    apply(T,:first,[[1,2,3]])
    #=> 1
    

    或者这个例子(下面的列表是Elixir List模块):

    apply(List,:first,[[1,2,3]]) 
    #=> 1
    

    我的意思是说,如果您知道模块的名称,则不必将其作为字符串传递,然后将字符串转换为现有原子 . 只需使用不带引号的名称 .

loading...

评论

暂时没有评论!