关于在模块内部调用宏

时间:2018-08-01 11:39:47

标签: elixir

defmodule DemoMacro do
  defmacro i_am_macro do
    quote do
      # ……
    end
  end

  i_am_macro # (CompileError) example.exs:10: undefined function i_am_macro/0
end

但是从其他模块导入的,可以成功调用:

defmodule SecondModule do
  require DemoMacro
  DemoMacro.i_am_macro
end

我应该怎么做才能使第一段代码编译?

1 个答案:

答案 0 :(得分:5)

您正在从模块主体中调用宏 ,这意味着在编译阶段。在编译器阶段,该模块的内容显然无法访问,因为该模块尚未编译。

将宏移至函数中

defmodule DemoMacro do
  defmacro i_am_macro do
    quote do
      IO.puts "Inside a macro"
    end
  end

  def test_macro(), do: i_am_macro()
end

DemoMacro.test_macro()
#⇒ "Inside a macro"

宏内容是在每个宏调用中注入的AST。在编译阶段,您可以使用已编译的Elixir代码。了解编译阶段和运行时之间的差异需要一定的思想转变,这主要是因为在两个阶段中,我们都使用相同的Elixir语法。但事实是,Elixir是一种编译语言,除非将其编译为BEAM,否则无法使用该代码。


您还可以在@after_compile回调中使用宏,在编译阶段,即BEAM模块可用(已编译)之后:

defmodule DemoMacro do
  defmacro i_am_macro do
    quote do
      IO.puts "Inside a macro"
    end
  end

  @after_compile __MODULE__

  def __after_compile__(env, _bytecode) do
    i_am_macro()
  end
end
#⇒ immediately prints "Inside a macro"