2015-12-10 1 views

答えて

63

パイプラインの機能を使用しているとき、あなたはモナドライブラリや巣のcase文を使用しなければならないのいずれか(プライベート関数を使用してリファクタリングすることができ、それでも冗長になってしまうでしょう) 。 with/1は、この問題を解決する別の方法を可能にします。ここで

original proposalからの例です。ここで

case File.read(path) do 
    {:ok, binary} -> 
    case :beam_lib.chunks(binary, :abstract_code) do 
     {:ok, data} -> 
     {:ok, wrap(data)} 
     error -> 
     error 
    end 
    error -> 
    error 
end 

は、機能を使用するためにリファクタリング同じものである:

path 
|> File.read() 
|> read_chunks() 
|> wrap() 

defp read_chunks({:ok, binary}) do 
    {:ok, :beam_lib.chunks(binary, :abstract_code)} 
end 
defp read_chunks(error), do: error 

defp wrap({:ok, data}) do 
    {:ok, wrap(data)} 
end 
defp wrap(error), do: error 

そしてwithを使用して、同じコード:

with {:ok, binary} <- File.read(path), 
    {:ok, data} <- :beam_lib.chunks(binary, :abstract_code), 
    do: {:ok, wrap(data)} 

これは、withは値が左側のパターンと一致する場合は連鎖します。そうでない場合、チェーンは中止され、最初に一致しない結果が返されます。ファイルが存在しない場合たとえば、その後File.read(path){:error, :enoent}を返します - これは{:ok, binary}と一致していませんので、with/1コールが{:error, :enoent}.

では、任意のパターンだけでなく、{:ok, foo}{:error, reason}(ただしで使用することができることは注目に値するを返します。非常に一般的な使用例です)。

+2

実際、「バージョンあり」ははるかに優れています。これは非常に便利です。 – diogovk

+0

私は 'defp read_chunks'の本文はちょうど':beam_lib.chunks(バイナリ、:抽象コード) 'を読むべきだと思っています(つまり、初期の{{:ok、'}なし) – Grandpa

+0

私はok_jose(https:// github。 com/vic/ok_jose)は、(名前を除いて)はるかにきれいに見えます。代わりにそれを使用しない理由はありますか? – Johannes

15

ます。また、チェーン「裸の表現」することができ、ドキュメントが言うように:

with {:ok, binary} <- File.read(path), 
    header = parse_header(binary), 
    {:ok, data} <- :beam_lib.chunks(header, :abstract_code), 
    do: {:ok, wrap(data)} 

変数headerだけwith文の中利用できるようになります。さらに詳しい情報はhttps://gist.github.com/josevalim/8130b19eb62706e1ab37

2

を指摘しておきたいことがありますが、withの説明文に記載されています。 例:

defmodule Test do 
    def test(res) do 
    with {:ok, decode_res} when is_map(decode_res) <- res 
    do 
     IO.inspect "ok" 
    else 
     decode_res when is_map(decode_res) -> IO.inspect decode_res 
     _ -> 
     IO.inspect "error" 
    end 
    end 
end 
Test.test({:ok , nil}) 
Test.test({:ok , 12}) 
Test.test({:ok , %{}}) 
関連する問題