来自__using __

时间:2017-11-09 14:00:42

标签: elixir

所以我想说我有一个模块App.A,它有以下代码

defmodule App.A do
  defmacro __using__(_) do
    quote do
      alias App.B
    end
  end
end

所以当它为used时,会自动为App.B添加别名。

现在,还有一个名为App.C的模块定义如下:

defmodule App.C do
  defmacro __using__(_) do
    quote do
      use App.A

      def foo do
        B.bar()
      end
    end
  end
end

添加了一个函数foo,它试图在没有显式调用模块B的情况下调用函数 别名,因为我希望使用App.A已经定义了一个别名。

现在问题是,当我有其他模块时,请说App.D uses App.C, 编译会给我一个警告,说B是未定义的,因此别名不起作用。

有人可以解释为什么会发生这种情况吗?

1 个答案:

答案 0 :(得分:2)

别名是使用它们的范围的本地。 quote宏的__using__块在调用模块的函数中执行,因此别名有效。但是,当调用use App.C时 - 别名不在该范围内,因此调用B.bar()将失败。

您可以将App.C更改为:

来验证这一点
defmodule App.C do
  defmacro __using__(_) do
    quote do
      use App.A

      IO.inspect B == App.B # false
      alias App.B
      IO.inspect B == App.B # true

      def foo do
        B.bar()
      end
    end
  end
end

你会注意到只要c.ex中存在别名,它就会起作用。您可以在使用它之前在文件中的任何位置定义它:

alias App.B
defmodule App.C do
  # alias App.B
  defmacro __using__(_) do
    # alias App.B
    quote do
      use App.A 
      # alias App.B

      def foo do
       # alias App.B
        B.bar()
      end
    end
  end
end