在Elixir中调用apply(String.t…)
如果模块名为字符串,如何调用模块的方法?我知道如何使用apply。如果模块的名称是字符串,如何使用它?您必须将字符串转换为atom。所有Elixir模块都位于在Elixir中调用apply(String.t…),elixir,Elixir,如果模块名为字符串,如何调用模块的方法?我知道如何使用apply。如果模块的名称是字符串,如何使用它?您必须将字符串转换为atom。所有Elixir模块都位于Elixir名称空间中(基本上是为了防止名称冲突),因此表示Elixir模块的原子都以Elixir开头。: iex(1)>defm模块,do:def foo,do:IO.puts“BAR” iex(2)>name=“M” iex(3)>apply(String.to_atom(“Elixir.”名称),:foo,[]) 酒吧 您必须将字符串
Elixir
名称空间中(基本上是为了防止名称冲突),因此表示Elixir模块的原子都以Elixir开头。
:
iex(1)>defm模块,do:def foo,do:IO.puts“BAR”
iex(2)>name=“M”
iex(3)>apply(String.to_atom(“Elixir.”名称),:foo,[])
酒吧
您必须将字符串转换为atom。所有Elixir模块都位于Elixir
名称空间中(基本上是为了防止名称冲突),因此表示Elixir模块的原子都以Elixir开头。
:
iex(1)>defm模块,do:def foo,do:IO.puts“BAR”
iex(2)>name=“M”
iex(3)>apply(String.to_atom(“Elixir.”名称),:foo,[])
酒吧
Elixir模块在使用和打印时,从名称中省略Elixir.
开头部分。编译Elixir和Erlang模块时,它们会生成一个beam文件。为了避免同名Elixir和Erlang的名称冲突,需要使用此前缀
当您编写和读取代码时,您不必考虑这一点,因为它是自动处理的。请注意,左侧和右侧都是原子。处理特殊符号时需要引号,模块只是以大写字母开头的原子,在这种情况下,可以省略:
iex(1)> :"Elixir.SomeModule" == SomeModule
true
iex(2)> :"Elixir.SomeModule" == Elixir.SomeModule
true
由于编译器会自动为您处理这些前缀,因此建议您在将字符串转换为模块名时也让编译器处理这些前缀
这可以通过使用Module.concat/1
和Module.safe\u concat/1
来完成。它们之间的区别在于,第一个使用二进制\u to_atom/2
,第二个使用二进制\u to_现有的\u atom/2
将字符串转换为原子。原子不是垃圾收集的,因此将随机用户输入作为二进制\u to \u atom/2
或其等效药剂String.to \u atom/1
的参数提供是危险的,因为这可能导致VM崩溃。在这个特定的用例中,如果您试图从一个不存在的模块调用一个函数,您将遇到错误
知道这一点后,Module.safe\u concat/1
功能是最合适的,因为:
- 它让编译器处理
前缀长生不老药。
- 它无法通过达到节点上允许的原子数限制而使VM崩溃
- 如果您提供的字符串与现有模块不对应,则会生成错误
iex(1)> Module.safe_concat(["String"]).upcase("xyz")
"XYZ"
当模块名称中有输入错误时引发错误:
iex(2)> Module.safe_concat(["Strign"]).upcase("xyz")
** (ArgumentError) argument error
:erlang.binary_to_existing_atom("Elixir.Strign", :utf8)
(elixir 1.12.0-dev) src/elixir_aliases.erl:126: :elixir_aliases.safe_concat/1
Elixir模块在使用和打印时,在其名称中省略
Elixir.
前导部分。编译Elixir和Erlang模块时,它们会生成一个beam文件。为了避免同名Elixir和Erlang的名称冲突,需要使用此前缀
当您编写和读取代码时,您不必考虑这一点,因为它是自动处理的。请注意,左侧和右侧都是原子。处理特殊符号时需要引号,模块只是以大写字母开头的原子,在这种情况下,可以省略:
iex(1)> :"Elixir.SomeModule" == SomeModule
true
iex(2)> :"Elixir.SomeModule" == Elixir.SomeModule
true
由于编译器会自动为您处理这些前缀,因此建议您在将字符串转换为模块名时也让编译器处理这些前缀
这可以通过使用Module.concat/1
和Module.safe\u concat/1
来完成。它们之间的区别在于,第一个使用二进制\u to_atom/2
,第二个使用二进制\u to_现有的\u atom/2
将字符串转换为原子。原子不是垃圾收集的,因此将随机用户输入作为二进制\u to \u atom/2
或其等效药剂String.to \u atom/1
的参数提供是危险的,因为这可能导致VM崩溃。在这个特定的用例中,如果您试图从一个不存在的模块调用一个函数,您将遇到错误
知道这一点后,Module.safe\u concat/1
功能是最合适的,因为:
- 它让编译器处理
前缀长生不老药。
- 它无法通过达到节点上允许的原子数限制而使VM崩溃
- 如果您提供的字符串与现有模块不对应,则会生成错误
iex(1)> Module.safe_concat(["String"]).upcase("xyz")
"XYZ"
当模块名称中有输入错误时引发错误:
iex(2)> Module.safe_concat(["Strign"]).upcase("xyz")
** (ArgumentError) argument error
:erlang.binary_to_existing_atom("Elixir.Strign", :utf8)
(elixir 1.12.0-dev) src/elixir_aliases.erl:126: :elixir_aliases.safe_concat/1
我只是想澄清一下-我认为您不需要
字符串。为了_atom(“Elixir.”name)
,模块名已经正确地转换为这种形式了@PawełDawczak我不确定我是否明白。模块名为,但String.to_atom(“M”)
返回:M
,而不是M
,它基本上由编译器处理并转换为Elixir.M
。这里我们手头没有编译器。我的观点是,我不认为你需要这样做:apply(String.to_atom(“Elixir.”name),:foo,[])
,因为这样做很好:apply(M,:foo,[])
,比如:apply(Kernel,:+,[1,2])。=>3
只是为了澄清-我不认为你需要String.to_atom(“Elixir.”name)
,模块名称已正确转换为此表单@PawełDawczak我不确定我是否明白。模块名为,但String.to_atom(“M”)
返回:M
,而不是M
,它基本上由编译器处理并转换为Elixir.M
。这里我们手头没有编译器。我的观点是,我认为您不需要这样做:apply(String.to_atom(“Elixir.”name),:foo,[])
,因为这样做很好:apply(M,:foo,[])
,比如:apply(内核,:+,[1,2])\