我有一个协议(protocol),它具有单一功能和相对复杂的 API:
defprotocol Foo do
def complex(foo, x, y)
end
我想提供一种方法来为常见且更简单的用例实现此协议(protocol)。经过一些实验,我得出以下结论:
defmodule Bar do
@callback simple(any, any) :: boolean
defmacro __using__(_) do
quote do
@behaviour Bar
defimpl Foo do
# TODO this is really hacky. What is a better way to reference parent module?
# Note that the 1 in drop(1) is from Foo's module name
@parent_module __MODULE__ |> Module.split |> Enum.drop(1) |> Module.concat
def complex(bar, x, _y) do
matches = @parent_module.simple(bar, x)
if matches, do: [x], else: []
end
end
end
end
end
现在我可以通过 use Bar
实现 Foo,但是 @parent_module
的确定和使用方式似乎是错误的。有没有比使用上面 TODO
中的 hack 更好的方法?执行此操作的惯用方法是什么?我宁愿不将 Foo
变成一种行为,因为协议(protocol)的调度和整合符合使用模式。
最佳答案
您可以获取父模块的名称并将其存储在局部变量中,然后将其放入实现中的属性中,然后使用它:
defmodule Bar do
@callback simple(any, any) :: boolean
defmacro __using__(_) do
quote do
@behaviour Bar
parent_module = __MODULE__
defimpl Foo do
@parent_module parent_module
def complex(bar, x, _y) do
matches = @parent_module.simple(bar, x)
if matches, do: [x], else: []
end
end
end
end
end
关于elixir - 在 Elixir 中用宏中的行为实现协议(protocol),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43788959/