将函数传递给defimpl“for”选项

时间:2017-10-10 11:13:38

标签: elixir

我有以下代码:

defprotocol Reversible do
  @doc "Reverses data structure"
  def reverse(term)
end

defimpl Reversible, for: [List, Map] do
  def reverse(term), do: Enum.reverse(term)
end

它工作正常,但我想以某种方式列出所有可枚举的类型,并在其他地方使用它们。

所以我试着这样做:

# constants.ex
defmodule Constants do
  @enumerables [List, Map]
  def enumerables, do: @enumerables
end

# reversible.ex
import Constants, only: [enumerables: 0]

defprotocol Reversible do
  def reverse(term)
end

defimpl Reversible, for: enumerables() do
  def reverse(term), do: Enum.reverse(term)
end

我有一个错误:

== Compilation error in file lib/reversible.ex ==
** (FunctionClauseError) no function clause matching in Module.concat/2

    The following arguments were given to Module.concat/2:

        # 1
        Reversible

        # 2
        [List, Map]

    (elixir) lib/module.ex:562: Module.concat/2
    lib/reversible.ex:8: (file)
    (elixir) lib/kernel/parallel_compiler.ex:121:
      anonymous fn/4 in Kernel.ParallelCompiler.spawn_compilers/1

如何解决这个问题?

1 个答案:

答案 0 :(得分:4)

defimpl检查for参数at compile time(宏参数)and if it's a list, it recurses over all items of the list的值。由于您的变量不是文字列表,defimpl不会将其视为列表。

您可以通过迭代列表并自己调用defimpl来解决此问题:

# constants.ex
defmodule Constants do
  @enumerables [List, Map]
  def enumerables, do: @enumerables
end

# reversible.ex
defprotocol Reversible do
  def reverse(term)
end

for enumerable <- Constants.enumerables do
  defimpl Reversible, for: enumerable do
    def reverse(term), do: Enum.reverse(term)
  end
end

测试:

$ iex -S mix
iex(1)> Reversible.reverse [1, 2, 3]
[3, 2, 1]
iex(2)> Reversible.reverse %{1 => 2, 3 => 4}
[{3, 4}, {1, 2}]