在使用回调中导入unquote(__ MODULE__)有什么作用?

Was*_*eem 2 elixir

在如下代码中:

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。是否将其导入自身?

Ale*_*kin 6

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()