有没有办法像 Ruby 那样从字符串插值中使用 Elixir 中的动态函数名称?
Is there a way to use a dynamic function name in Elixir from string interpolation like in Ruby?
我希望能够从 elixir 中的字符串构造函数调用。这可能吗?等效的 ruby 方法调用是:
"uppercase".send("u#{:pcase}")
在 Elixir 模块和函数名中都是原子。您可以使用 apply
动态调用它们。
apply(String, String.to_atom("u#{:pcase}"), ["uppercase"]) # "UPPERCASE"
根据您的用例,动态创建原子可能不是一个好主意(因为原子 table 未被垃圾收集)。
虽然@fhdhsni 的回答是完全正确的,但我会添加一些吹毛求疵的说明。
完全等同于 ruby in elixir is impossible, because Kernel#send
allows to call private methods on the receiver. In elixir 中的 Kernel#send
,编译后的代码中永远不会存在私有函数。
如果您的意思是 Kernel#public_send
,则可以用 Kernel.apply/3
, as mentioned by @fhdhsni. The only correction is since the atom table is not garbage collected, and one surely wants to call an indeed existing function, it should be done with String.to_existing_atom/1
来实现。
apply(
String,
String.to_existing_atom("u#{:pcase}"),
["uppercase"]
)
此外,当要调用的函数列表是可预测的(如果不是,代码已经有味道)时,人们可能会在编译阶段使用宏来生成相应的子句。
defmodule Helper do
Enum.each(~w|upcase|a, fn fname ->
def unquote(fname)(param),
do: String.unquote(fname)(param)
# or
# defdelegate unquote(fname)(param), to: String
end)
end
Helper.upcase("uppercase")
#⇒ "UPPERCASE"
我希望能够从 elixir 中的字符串构造函数调用。这可能吗?等效的 ruby 方法调用是:
"uppercase".send("u#{:pcase}")
在 Elixir 模块和函数名中都是原子。您可以使用 apply
动态调用它们。
apply(String, String.to_atom("u#{:pcase}"), ["uppercase"]) # "UPPERCASE"
根据您的用例,动态创建原子可能不是一个好主意(因为原子 table 未被垃圾收集)。
虽然@fhdhsni 的回答是完全正确的,但我会添加一些吹毛求疵的说明。
完全等同于 ruby in elixir is impossible, because Kernel#send
allows to call private methods on the receiver. In elixir 中的 Kernel#send
,编译后的代码中永远不会存在私有函数。
如果您的意思是 Kernel#public_send
,则可以用 Kernel.apply/3
, as mentioned by @fhdhsni. The only correction is since the atom table is not garbage collected, and one surely wants to call an indeed existing function, it should be done with String.to_existing_atom/1
来实现。
apply(
String,
String.to_existing_atom("u#{:pcase}"),
["uppercase"]
)
此外,当要调用的函数列表是可预测的(如果不是,代码已经有味道)时,人们可能会在编译阶段使用宏来生成相应的子句。
defmodule Helper do
Enum.each(~w|upcase|a, fn fname ->
def unquote(fname)(param),
do: String.unquote(fname)(param)
# or
# defdelegate unquote(fname)(param), to: String
end)
end
Helper.upcase("uppercase")
#⇒ "UPPERCASE"