我工作过戴维的即将出版的新书在花好月圆我的方式,并且在一个锻炼,我想动态构造函数引用Kernel.+/2
,Kernel.-/2
等等,基于一个字符串的一个字符的内容'+'
,'-'
等等.
基于另一个SO问题,我希望能够调用apply/3
传递内核,:+和这两个数字:
apply(Kernel, :+, [5, 7])
这不起作用,因为(如果我理解的话)Kernel.+/2
是一个宏,而不是一个函数.我查找了源代码,并根据+
其定义__op__
,我可以从iex
以下地址调用它:
__op__(:+, 5, 7)
这有效,直到我将:+放入变量:
iex(17)> h = list_to_atom('+') :+ iex(18)> __op__(h, 5, 7) ** (CompileError) iex:18: undefined function __op__/3 src/elixir.erl:151: :elixir.quoted_to_erl/3 src/elixir.erl:134: :elixir.eval_forms/4
而且我猜测没有办法打电话__op__
使用apply/3
.
当然,蛮力方法可以完成工作.
defp _fn(?+), do: &Kernel.+/2 defp _fn(?-), do: &Kernel.-/2 defp _fn(?*), do: &Kernel.*/2 # defp _fn(?/), do: &Kernel.//2 # Nope, guess again defp _fn(?/), do: &div/2 # or &(&1 / &2) or ("#{div &1, &2} remainder #{rem &1, &2}")
但是有更简洁和动态的东西吗?
JoséValim在下面给出了答案.这是上下文中的代码:
def calculate(str) do {x, op, y} = _parse(str, {0, :op, 0}) apply :erlang, list_to_atom(op), [x, y] end defp _parse([] , acc ) , do: acc defp _parse([h | t], {a, b, c}) when h in ?0..?9, do: _parse(t, {a, b, c * 10 + h - ?0}) defp _parse([h | t], {_, _, c}) when h in '+-*/', do: _parse(t, {c, [h], 0}) defp _parse([_ | t], acc ) , do: _parse(t, acc)
José Valim.. 9
你可以使用Erlang:
apply :erlang, :+, [1,2]
我们意识到这是令人困惑的,我们正在研究制定或更明确或更透明的方法.
更新:自Elixir 1.0以来,您可以直接调度到Kernel(apply Kernel, :+, [1, 2]
),甚至可以使用OP首先尝试的语法(&Kernel.+/2
).
你可以使用Erlang:
apply :erlang, :+, [1,2]
我们意识到这是令人困惑的,我们正在研究制定或更明确或更透明的方法.
更新:自Elixir 1.0以来,您可以直接调度到Kernel(apply Kernel, :+, [1, 2]
),甚至可以使用OP首先尝试的语法(&Kernel.+/2
).