为什么可以在宏外部调用`unquote`?

时间:2016-02-19 21:18:03

标签: elixir

h unquote说“从宏内部取消引用给定的表达式。”

但是,我刚刚看到unquote可以在宏外部使用的方式。

defmodule Example do
  x = 4
  def foo do
    unquote(x)
  end

  x = 5
  def bar do
    x = 4
    "#{unquote(x)}, #{x}"
  end
end

IO.puts Example.foo #=> 4
IO.puts Example.bar #=> "5, 4"

这是unquote相同还是不同?这是一个功能还是一个bug? (它似乎与"temporary storage" purpose of module attributes重叠。)

为什么我可以在宏unquote之外拨打quote

2 个答案:

答案 0 :(得分:3)

这是有效的,因为def本身是一个用defmacro实现的宏,并返回一个带引号的表达式。因此,虽然看起来你不在引用的表达式中,因为你没有调用quote,实际上你是。

https://github.com/elixir-lang/elixir/blob/928302a912e397917be957142a9837ae58610207/lib/elixir/lib/kernel.ex#L3225L3227

还有其他地方也适用,例如在ExUnit测试中(同样是因为test宏使用def来定义函数。https://github.com/elixir-lang/elixir/blob/928302a912e397917be957142a9837ae58610207/lib/ex_unit/lib/ex_unit/case.ex#L256

答案 1 :(得分:3)

最简单的答案是模块中的所有内容都在隐式quote内。

特别是这在defmodule的定义中完成(这只是一个常规宏):https://github.com/elixir-lang/elixir/blob/master/lib/elixir/lib/kernel.ex#L3008

为什么需要这个? Elixir编译器适用于AST,获取AST的唯一方法是引用代码。

免责声明:这是我对正在发生的事情的理解。关于为什么这样做的真相可能会有所不同。