macros - Elixir 宏和 bind_quoted

标签 macros metaprogramming elixir

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

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/

相关文章:

c - 使用C中的宏为t数组赋值

php - 如何在 Laravel 5.4 中创建带有彩色 <option> 元素的下拉列表?

c - 使用宏获得的输出说明

julia - 如何在 Julia 中创建一个计算结果为 Expr 的 Expr?

python动态设置非实例类属性

elixir - 使用带有 iex -S mix phoenix.server 的 webpack 时如何摆脱 ^H?

c - 在 gcc 语句表达式中声明一个数组并返回指向它的指针?

Java:引用类型?

elixir - 这两种代码方法之间有什么重要区别吗?

api - 使用 httpotion elixir 发布到 slack api