2016-10-14 8 views
0

私はエリクシルでプロトコルを定義し、いくつかのモジュールでそれを実装したかったのです。私の問題は、そう、これらのモジュールは、単にエージェントラッパーであるということです。エリクシールでエージェントを使ってプロトコルを実装する

、その後に結果
defprotocol Proto do 
    def foo(proto) 
end 

defmodule A do 
    def start_link() do 
    Agent.start_link(fn -> :a end) 
    end 
end 

defimpl Proto, for: A do 
    def foo(proto) do 
    Agent.get(proto, fn a -> a end) 
    end 
end 

defmodule B do 
    def start_link() do 
    Agent.start_link(fn -> :b end) 
    end 

end 

defimpl Proto, for: B do 
    def foo(proto) do 
    Agent.get(proto, fn b -> b end) 
    end 
end 

{:ok, a_pid} = A.start_link() 
value = Proto.foo(a_pid) 

** (Protocol.UndefinedError) protocol Proto not implemented for #PID<0.88.0> 
    test.exs:1: Proto.impl_for!/1 
    test.exs:2: Proto.foo/1 
    (elixir) lib/code.ex:363: Code.require_file/2 

が直接これを処理する方法はありますか?

答えて

2

このようなプロトコルを使用するには、AB構造体を作成し、それぞれstart_link関数から返す必要があります。 Agent関数を呼び出すには、Agentのラッパーも必要です。

defprotocol Proto do 
    def foo(proto) 
end 

defmodule A do 
    defstruct [:pid] 

    def start_link() do 
    WrappedAgent.start_link(A, fn -> :a end) 
    end 
end 

defimpl Proto, for: A do 
    def foo(proto) do 
    WrappedAgent.get(proto, fn a -> {:a, a} end) 
    end 
end 

defmodule B do 
    defstruct [:pid] 

    def start_link() do 
    WrappedAgent.start_link(B, fn -> :b end) 
    end 
end 

defimpl Proto, for: B do 
    def foo(proto) do 
    WrappedAgent.get(proto, fn b -> {:b, b} end) 
    end 
end 

defmodule WrappedAgent do 
    def start_link(module, f) do 
    with {:ok, pid} <- Agent.start_link(f), 
     do: {:ok, %{__struct__: module, pid: pid}} 
    end 

    def get(%{pid: pid}, f), do: Agent.get(pid, f) 
end 

{:ok, a} = A.start_link() 
IO.inspect Proto.foo(a) 

{:ok, b} = B.start_link() 
IO.inspect Proto.foo(b) 

は出力::あなたは同じ構造でより多くの構造体を作成した場合と同じに再利用することができますので、私はこのために別のモジュールを作成した

{:a, :a} 
{:b, :b} 
+0

パーフェクト!ありがとうございました。私はエリクシールの世界には新しいので、言語の哲学を理解するのには少しの道のりがあります。 –

2

だけビットを明確にするために、プロトコルが実装されていますデータ型。モジュールで定義したすべての標準データ型と構造体に対して、プロトコルを実装できます。

[Atom, Integer, Float, BitString, Regexp, PID, Function, Reference, Port, Tuple, List, Map] 

"同じ機能、異なるデータタイプ"と考えてください。元のアイデアに近い行動とは対照的です。ここでは、他のモジュール が標準的な方法であなたのモジュールを使用できるようにモジュールで実装するものと同じアリティ(そして同じ慣習的な入力)を持つ関数のセットを定義します。

関連する問題