我的协议具有单一功能,并且具有相对复杂的API:
defprotocol Foo do
def complex(foo, x, y)
end
我想提供一种方法来实现此协议,以实现常见且更简单的用例。经过一些实验,我想出了以下内容:
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
中的黑客更好的方法?这样做的惯用方法是什么?我宁愿不将Foo
变成一种行为,因为协议的调度和合并符合使用模式。
答案 0 :(得分:3)
您可以在本地变量中获取并存储父模块的名称,然后将其放在实现中的属性中,然后使用它:
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