在如下代码中:
defmodule ModuleToBeUsed do
defmacro __using__(_) do
quote do
import unquote(__MODULE__)
end
end
end
defmodule ModuleUsing do
use ModuleToBeUsed
end
Run Code Online (Sandbox Code Playgroud)
这条线是import unquote(__MODULE__)做什么的?__MODULE__是指ModuleUsing。是否将其导入自身?
Elixir(以及erlang)有两个 “执行”阶段。在编译阶段将“执行”代码以产生光束;第二个阶段是“执行”。之后,代码在“执行”阶段执行(我知道这听起来有点麻烦,但是下面的代码将有助于您了解发生了什么。)
考虑以下代码:
$ cat /tmp/test.ex
defmodule ModuleToBeUsed do
defmacro __using__(_) do
IO.puts __MODULE__ # COMPILATION STAGE
quote do # needed to prevent execution on compilation stage
import unquote(__MODULE__)
def test, do: IO.puts "I am test" # EXECUTION STAGE
end
end
end
defmodule ModuleUsing do
use ModuleToBeUsed
def test_of_test, do: test() # I can call `test` here!
end
ModuleUsing.test_of_test()
Run Code Online (Sandbox Code Playgroud)
上面的代码将输出
Elixir.ModuleToBeUsed # from compilation stage
I am test # on execution stage
Run Code Online (Sandbox Code Playgroud)
删除最后一个实际的调用ModuleUsing.test_of_test(),您仍然会看到第一个输出(带有模块名称。)
现在回到您的问题。quote do: import unquote(__MODULE__)宏中的内容将被编译为import(原样)ModuleToBeUsed(由于unquote它将在编译阶段进行扩展。)在执行阶段将强制ModuleUsing导入ModuleToBeUsed。制作一个电话test()可能没有命名空间(另有一个应该被调用它ModuleToBeUsed.test()。