我有一个宏定义这样的模块。
defmodule Bar do
def bar do
IO.puts "I am #{inspect __MODULE__}"
end
end
defmodule MacroFun do
defmacro define_module(name) do
quote do
defmodule unquote(name) do
import Bar
def foo do
bar
IO.puts "I am #{inspect __MODULE__}"
end
end
end
end
end
defmodule Runner do
require MacroFun
def run do
MacroFun.define_module Foo
Foo.foo
end
end
Runner.run
运行此命令的输出是:
I am Bar
I am Runner.Foo
这是有道理的;
MacroFun.define_module
在Runner.run
中被调用,因此模块被定义并嵌套在Runner
模块下。但是现在,如果我将
MacroFun.define_module
更改为使用:bind_quoted
选项: defmacro define_module(name) do
quote bind_quoted: [name: name] do
defmodule name do
import Bar
def foo do
bar
IO.puts "I am #{inspect __MODULE__}"
end
end
end
end
现在的输出变为:
I am Bar
I am Foo
为什么??
最佳答案
我认为这是因为您取消引用(绑定(bind))变量name
的位置。
在第一种情况下,您在创建模块时取消引用变量name
,因此此时绑定(bind)变量将需要检查上下文(例如,检查代码是否在另一个模块内)。因此,您将获得当前的原子以及适当的上下文:Runner.Foo
。
在第二种情况下,您要先将变量name
放在上下文中,然后再将其取消引用,因此其值不会改变,它将是Foo
原子(无上下文)。
关于macros - Elixir宏和bind_quoted,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34889369/