【发布时间】:2019-03-05 08:49:01
【问题描述】:
我正在尝试实现 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
这段代码忽略了一些与字段相关的宏细节,但主要思想就像我上面说的一样。此代码无法编译,因为即使在调用 Code.ensure_loaded(Bar) 时,编译 Foo 时 Bar 也不可用。我需要这个,因为我想在编译时而不是运行时运行一些代码来节省一些时间。
如果 Bar 在 Foo 之前或在另一个文件中定义,它会起作用。但在 protobuf 生成的文件中很难确保这一点。
有没有办法解决这个问题?
【问题讨论】:
-
我在编译顺序方面做得不多。
require Bar会有帮助吗?我不知道它到底是做什么的,但它对宏的作用,我认为它会在这里工作。 -
是的,就我最近对
Code.ensure_loaded和require的实验来看,require是唯一的方法,前者并不总是有效
标签: elixir