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

时间:2016-12-19 21:41:11

标签: elixir

在以下代码中:

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

2 个答案:

答案 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。此代码将无法编译,因为它会创建循环依赖。