elixir – 如何使用Kernel.apply进行宏功能

elixir的
Kenel.apply/3 function无法调用由宏定义的函数.

例,

defmodule Hoge1 do
  for fun_name <- [:foo, :bar] do
    defmacro unquote(fun_name)(arg) do
      apply(Hoge2, unquote(fun_name), [arg])
    end
  end
end

defmodule Hoge2 do
  for fun_name <- [:foo, :bar] do
    defmacro unquote(fun_name)(arg) do
      IO.puts "hoge2"
    end
  end
end

在上面的情况下,如果我调用Hoge1.foo,则会出错.
(未定义的函数:Hoge2.foo/1)

我可以直接打电话给Hoge2.foo/1.
(输出“hoge2”)

我可以使用Kernel.apply / 3调用吗?

最佳答案 apply仅适用于函数,不适用于宏.首先,检查一下你是否真的需要宏,因为很多问题可以(并且应该)只用函数来解决.在这种情况下,您可以使用def代替defmacro:

defmodule Hoge1 do
  for fun_name <- [:foo, :bar] do
    def unquote(fun_name)(arg) do
      apply(Hoge2, unquote(fun_name), [arg])
    end
  end
end

defmodule Hoge2 do
  for fun_name <- [:foo, :bar] do
    def unquote(fun_name)(arg) do
      IO.puts "hoge2"
    end
  end
end

如果您的解决方案严格要求宏,您可以直接生成宏调用,而不是使用apply:

Hoge2.unquote(fun_name)(arg)

要使Hoge1宏可用于Hoge1,您还需要在Hoge1内部使用Hoge2.完整的解决方案看起来像这样

defmodule Hoge2 do
  for fun_name <- [:foo, :bar] do
    defmacro unquote(fun_name)(arg) do
      IO.puts "hoge2"
    end
  end
end

defmodule Hoge1 do
  require Hoge2

  for fun_name <- [:foo, :bar] do
    defmacro unquote(fun_name)(arg) do
      Hoge2.unquote(fun_name)(arg)
    end
  end
end
点赞