是否可以通过“ use / 2”宏(用于DRY)扩展Elixir协议?

问题描述 投票:0回答:1

我有一个项目,需要定义一些名称不同但定义完全相同的协议。

我尝试用use/2来做到这一点,但是没有运气:它不起作用,从__using__/1进行的定义不会出现在结果协议中:

defmodule Action do
  defmacro __using__(_) do
    quote do
      def run(tool)
    end
  end
end

defprotocol Actions.ShowId do
  use Action
end

defmodule Tools.SimpleRelay do
  defstruct [:id]

  defimpl Actions.ShowId do
    def run(%Tools.SimpleRelay{id: id}), do: IO.puts(inspect(id))
  end
end

关于具有协议实现定义的结构,我得到:

warning: module Actions.ShowId is not a behaviour (in module Actions.ShowId.Tools.SimpleRelay)
  iex:8: Actions.ShowId.Tools.SimpleRelay (module)

如果我尝试使用它:

iex(6)> relay = struct(Tools.SimpleRelay, id: "ALongStringId")
%Tools.SimpleRelay{id: "ALongStringId"}
iex(7)> Actions.ShowId.run(relay)
** (UndefinedFunctionError) function Actions.ShowId.run/1 is undefined or private
    Actions.ShowId.run(%Tools.SimpleRelay{id: "ALongStringId"})

是错误还是目的?还是只是我的定义不正确?

我曾尝试在elixirforum上问同样的问题(并将此任务背景张贴在此),到目前为止,我唯一的建议是这是一个错误。在打开问题之前,我想澄清一下它确实是一个错误。

谢谢!

elixir
1个回答
0
投票

Kernel.defprotocol/2委派给Kernel.defprotocol/2,然后通过取消导出Protocol.__protocol__/2并导入Protocol.__protocol__/2来依次委派redefines def/2。在您的宏上下文中,def/2宏指的是导入的ATM Kernel.def/2,它破坏了所需的行为。

我不确定这是否是错误,但是您可以通过使用FQN调用Protocol.def/1 明确地来轻松解决它。

def
© www.soinside.com 2019 - 2024. All rights reserved.