繁体   English   中英

Elixir 1.3中的宏和模块属性

[英]Macros and module attributes in Elixir 1.3

Elixir 1.3.0-rc1编译器无法编译我的一个宏。 在Elixir 1.2.6中没问题。

defmodule M do
  defmacro ifa(a, exp) do
    if (Macro.expand_once(a, __ENV__)), do: exp
  end
end

defmodule Foo do
  @flag true

  require M
  def main do
    M.ifa (@flag), do: IO.puts 123
  end
end

Foo.main

编译器抱怨该属性。

% /tmp/elixir-1.3.0-rc1/bin/elixir foobar.exs
** (ArgumentError) could not call get_attribute on module M because it was already compiled
    (elixir) lib/module.ex:1144: Module.assert_not_compiled!/2
    (elixir) lib/module.ex:1066: Module.get_attribute/3
    (elixir) lib/kernel.ex:2360: Kernel.do_at/4
    (elixir) expanding macro: Kernel.@/1
    foobar.exs:12: M.ifa/2
    expanding macro: M.ifa/2
    foobar.exs:12: Foo.main/0


% /tmp/elixir-1.2.6/bin/elixir foobar.exs
123

我想知道为什么在扩展宏之前编译Foo。 什么在1.3中改变了?

Elixir实际上在您的代码中发现了一个错误! :d

在宏中,当您使用__ENV__ ,您将在定义宏的模块的上下文中扩展用户引用的表达式,而不是在调用者的上下文中。 解决方案是使用__CALLER__来确保在Elixir v1.2和v1.3中使用Foo的上下文正确扩展@flag

defmodule M do
  defmacro ifa(a, exp) do
    if (Macro.expand_once(a, __CALLER__)), do: exp
  end
end

感谢您试用Elixir v1.3-rc!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM