在以下代码中:
defmodule ModuleToBeUsed do
defmacro __using__(_) do
quote do
import unquote(__MODULE__)
end
end
end
defmodule ModuleUsing do
use ModuleToBeUsed
end
import unquote(__MODULE__)
行有什么作用? __MODULE__
是指ModuleUsing
。是将它导入自身吗?
答案 0 :(得分:5)
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()
上面的代码将输出
Elixir.ModuleToBeUsed # from compilation stage
I am test # on execution stage
删除对ModuleUsing.test_of_test()
的最后一次实际调用,您仍会看到第一个输出(带有模块名称。)
现在回到你的问题。宏中的quote do: import unquote(__MODULE__)
将编译为import
(按原样)ModuleToBeUsed
(由于unquote
,它将在编译阶段扩展。)在执行阶段,将强制ModuleUsing
导入ModuleToBeUsed
。在没有命名空间的情况下调用test()
是可能的(否则应该将其称为ModuleToBeUsed.test()
。
答案 1 :(得分:1)
在您的代码中,__MODULE__
指的是ModuleToBeUsed
。此代码将无法编译,因为它会创建循环依赖。