关于在模块内部调用宏

Hen*_*_Cl 2 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
Run Code Online (Sandbox Code Playgroud)

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

defmodule SecondModule do
  require DemoMacro
  DemoMacro.i_am_macro
end
Run Code Online (Sandbox Code Playgroud)

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

Ale*_*kin 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"
Run Code Online (Sandbox Code Playgroud)

宏内容是在每次宏调用时就地注入的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"
Run Code Online (Sandbox Code Playgroud)