如何在Elixir中的同一文件中加载其他模块之前加载模块?

如何在Elixir中的同一文件中加载其他模块之前加载模块?,elixir,Elixir,我正在尝试实现Protobuf的一些特性,我有一个例子:一个模块需要在编译时调用另一个模块。它们在同一个文件中,很难确保它们的顺序 defmodule FakeProtobuf do defmacro __using__(opts) do quote do # register_attribute fields and set fields @before_compile FakeProtobuf end end defmacro __bef

我正在尝试实现Protobuf的一些特性,我有一个例子:一个模块需要在编译时调用另一个模块。它们在同一个文件中,很难确保它们的顺序

defmodule FakeProtobuf do
  defmacro __using__(opts) do
    quote do
      # register_attribute fields and set fields
      @before_compile FakeProtobuf
    end
  end

  defmacro __before_compile__(_) do
    # result = Enum.map(fields, fn ...)

    # even Code.ensure_loaded doesn't work
    result = %{bar: Bar.default}
    quote do
      def default do
        unquote(Macro.escape(result))
      end
    end
  end
end

defmodule Foo do
  use FakeProtobuf
  # field :bar, type: Bar
end

defmodule Bar do
  def default do
    "bar"
  end
end
在这段代码中,一些与字段相关的宏细节被忽略,但其主要思想与我上面所说的一样。无法编译此代码,因为编译Foo时,即使在
code时,Bar也不可用。请确保调用\u loaded(Bar)
。我之所以需要它,是因为我想在编译时而不是运行时运行一些代码来节省时间

如果在Foo之前或在另一个文件中定义了Bar,则它可以工作。但在protobuf生成的文件中很难确保这一点


还有什么办法可以解决这个问题吗?

我只需在其他模块之前定义
Bar
,就可以编译您的代码

当编译器开始编译模块时,它不知道该模块中的定义

它开始编译文件,并在编译/1宏之前遇到您的
\u。当扩展该宏时,它需要调用模块
B
中的一个函数,而编译器还没有看到该函数,因此它会出错

** (UndefinedFunctionError) function Bar.default/0 is undefined (module Bar is not available)
为了解决这个问题,我们在定义
FakeProtoBuf
模块之前移动
Bar
模块。这样编译器就可以安全地调用该函数,因为
Bar
将被完全编译

最后,编译器将编译
Foo
,它将使用
FakeProtoBuf
中的\uuuu1
执行
,这将在编译之前注入
,从而在
FakeProtoBuf
模块中调用宏
\uuuuu-before-compile\uuuu

  def default do
    "bar"
  end
end

defmodule FakeProtobuf do
  defmacro __using__(_opts) do
    quote do
      # register_attribute fields and set fields
      @before_compile FakeProtobuf
    end
  end

  defmacro __before_compile__(_) do
    result = %{bar: Bar.default()}

    quote do
      def default do
        unquote(Macro.escape(result))
      end
    end
  end
end

defmodule Foo do
  use FakeProtobuf
  # field :bar, type: Bar
end

我可以通过在其他模块之前定义
Bar
来编译代码

当编译器开始编译模块时,它不知道该模块中的定义

它开始编译文件,并在编译/1
宏之前遇到您的
\u。当扩展该宏时,它需要调用模块
B
中的一个函数,而编译器还没有看到该函数,因此它会出错

** (UndefinedFunctionError) function Bar.default/0 is undefined (module Bar is not available)
为了解决这个问题,我们在定义
FakeProtoBuf
模块之前移动
Bar
模块。这样编译器就可以安全地调用该函数,因为
Bar
将被完全编译

最后,编译器将编译
Foo
,它将使用
FakeProtoBuf
中的\uuuu1
执行
,这将在编译之前注入
,从而在
FakeProtoBuf
模块中调用宏
\uuuuu-before-compile\uuuu

  def default do
    "bar"
  end
end

defmodule FakeProtobuf do
  defmacro __using__(_opts) do
    quote do
      # register_attribute fields and set fields
      @before_compile FakeProtobuf
    end
  end

  defmacro __before_compile__(_) do
    result = %{bar: Bar.default()}

    quote do
      def default do
        unquote(Macro.escape(result))
      end
    end
  end
end

defmodule Foo do
  use FakeProtobuf
  # field :bar, type: Bar
end

我对编译顺序做得不多。
要求条形码有帮助吗?我不知道它到底是做什么的,但就它对宏的作用而言,我认为它在这里会起作用。是的,
require
是我从最近的
代码实验中可以看出的唯一方法。确保加载的
require
,前者并不总是起作用。我对编译顺序做得不多。
要求条形码有帮助吗?我不知道它到底是做什么的,但就它对宏的作用而言,我认为它在这里会起作用。是的,
require
是我从最近对
代码的实验中可以看出的唯一方法。确保加载了
require
,前者并不总是有效的,但问题是要保证模块的顺序有点困难,因为代码是生成的。修复生成代码的东西。或者将它们放在单独的文件中。但问题是,要保证模块的顺序有点困难,因为代码是生成的。老实说,这就是你的问题。修复生成代码的东西。或者把它们放在不同的文件中。