我有一个宏,它定义了这样的模块。
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
这是有道理的;在 Runner.run
中调用了 MacroFun.define_module
,因此模块被定义并嵌套在 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/