间隔写上一篇文章曾经过来了将近1年工夫。
应用elixir进行元编程的时候,初学者常常会不分明模块的编译程序。咱们用一个简略的例子来解释一下。
defmodule M1 do @after_compile M0 @before_compile M0 use M0 @a 1 @a 2end
咱们定义了一个 M1 模块,它应用了几个 elixir 内置的模块属性:
@after_compile M0
示意在 M1 模块编译之后,调用M0.__after_compile__
@before_compile M0
示意在 M1 模块编译之前,调用M0.__before_compile__
接着咱们定义 M0
模块, 在每个hook被调用时打印相干的信息:
defmodule M0 do defmacro __using__(_) do mod = __CALLER__.module Module.register_attribute mod, :a, accumulate: true IO.puts "#{__MODULE__} being used by #{mod}" end defmacro __after_compile__(_, _) do IO.puts "#{__MODULE__} after compile be called" end defmacro __before_compile__(_) do IO.puts "#{__MODULE__} before compile be called" Module.get_attribute(__CALLER__.module, :a) |> IO.inspect(label: "#{__CALLER__.module} has attribute a") endend
惊人的一幕产生了,咱们看到了这样的程序:
Elixir.M0 being used by Elixir.M1Elixir.M0 before compile be calledElixir.M1 has attribute a: [2, 1]Elixir.M0 after compile be called
论断是,在 elixir 编译器编译一个模块的时候,hooks 依照这样的程序被调用的:
__using__
- module attributes 被编译
__before_compile__
__after_compile__