有没有办法像 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 的回答是完全正确的,但我会添加一些吹毛求疵的说明。

完全等同于 in is impossible, because Kernel#send allows to call private methods on the receiver. In 中的 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"