我有一个宏定义这样的模块。

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_moduleRunner.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/

10-11 00:49