elixir - 关于在模块内调用宏

标签 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

我应该怎么做才能让第一段代码通过?

最佳答案

从模块主体调用宏,意思是在编译阶段。在编译阶段,这个模块的内容显然是不可访问的,因为模块还没有编译。

将宏移动到一个函数中:

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,在每次宏调用时被注入(inject)到位。在编译阶段,您可能会使用已经编译的 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"

关于elixir - 关于在模块内调用宏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51632346/

相关文章:

phoenix-framework - 如何在phoenix框架聊天应用程序中向不同用户发送消息

elixir - 在 Elixir 中,put_in 中的叶节点是列表,而不是映射

functional-programming - 检查列表中的所有元素是否都有 :ok element

erlang - 连接关闭 - 奇怪的错误,无法从 erlang VM 连接到某些主机

mongodb - 如何使用 Ecto 更新嵌入列表中的一个子文档?

json - JSON响应的限制字段

elixir - Plug 路由器是否需要匹配/调度管道?

elixir - 混合测试 - 测试模式与任何文件都不匹配

string - Elixir:将整数转换为 unicode 字符

elixir - 如何使用 Elixir 宏创建动态函数名称?