为什么动态调用会导致“未定义的函数”?

时间:2018-07-24 04:56:46

标签: macros elixir metaprogramming

我有一个模块,可以通过以下方式将外部调用动态路由到其自身的功能:

L1 55.596893310546875
L2 2.15625
L3 68.87890625

模块已成功编译,并且defmodule A do defmacro call(name) do quote do fun = & unquote(:"A.#{name}")(&1) fun.(:foo) end end def test(param), do: IO.inspect(param, label: "test") end #⇒ {:module, A, ..., {:test, 1}} 在那里。

A.test/1

现在,我尝试将其称为:

A.test :foo
#⇒ test: :foo

这种动态呼叫分配有什么问题,为什么错误消息与现实矛盾呢?

1 个答案:

答案 0 :(得分:2)

该错误消息具有误导性。 & unquote(:"A.#{name}")(&1)将在当前范围内调用一个名为A.test的函数,而不是模块test/1的{​​{1}}函数:

A

输出:

defmodule A do
  defmacro call(name) do
    quote do
      fun = & unquote(:"A.#{name}")(&1)
      fun.(:foo)
    end
  end

  def unquote(:"A.test")(param), do: IO.inspect(param, label: "!!!")
end

defmodule B do
  require A
  import A
  def test, do: A.call(:test)
end

B.test

要使其调用模块!!!: :foo 的{​​{1}}函数,可以执行test/1

A

输出:

& A.unquote(:"#{name}")(&1)