我想生成一个使用宏创建函数的模块,一切都按预期工作但除了unquote(块)上下文似乎超出预期。 测试代码如下。
defmodule A do
defmacro wrap(head,opts \\[],do: block) do
{name,args} = case head do
name when is_atom(name) ->
{name,[]}
h ->
Macro.decompose_call h
end
quote do
def unquote(name)(unquote_splicing(args)) do
IO.inspect __ENV__
unquote(block)
end
end
end
end
defmodule B do
import A,only: [wrap: 2]
alias B.C
wrap test do
C.test2
end
end
defmodule C do
def test do
quote do
import A,only: [wrap: 2]
alias B.C
wrap test do
IO.inspect __ENV__
C.test2
end
end
end
end
defmodule B.C do
def test2 do
"good"
end
end
Module.create D,C.test,__ENV__
模块B应与D相同,除了D是动态生成的模块,B是预定义的模块。 当调用B.test时,它正确地将C解析为B.C并返回“good”作为结果。 但是当调用D.test时,它引发了无法找到C的异常((UndefinedFunctionError)未定义函数C.test2 / 0)
有没有人对这个问题的根源有一些见解?任何帮助都会得到真正的赞赏。请事先提供帮助;)
确认为错误并已修复
答案 0 :(得分:0)
基本上,引用块未正确解析别名B.C
。如果你直接在块内引用它,问题就会消失。我不确定为什么会这样。具有相同当前模块名称的别名可能使调用不明确。无论哪种方式,您都可以通过将C
模块重写为以下内容来解决此问题:
defmodule C do
def test do
quote do
import A, only: [wrap: 2]
wrap test do
IO.inspect __ENV__
B.C.test2
end
end
end
end
结果如下:
iex(1)> D.test
"good"
** 更新:
此别名问题似乎确实是一个错误。插入alias
后,宏打印输出会显示C
和B.C
都列为别名,但它仍然无法正常工作。我还验证了当前的模块名称没有引起冲突问题。