2015-12-10 4 views

Antwort

63

In Versionen von Elixir vor 1.2, wenn Funktionen in einer Pipeline verwenden, würden Sie haben entweder eine Monade Bibliothek oder Nest Case-Anweisungen verwenden (die mit privaten Funktionen Refactoring werden könnte, aber nach wie vor würden seine ausführlichen am Ende) . with/1 ermöglicht eine andere Möglichkeit, dieses Problem zu lösen. Hier

ist ein Beispiel aus der 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 

Hier ist die gleiche Sache Refactoring-Funktionen verwenden:

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 

Und der gleiche Code with mit:

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

Dies funktioniert, weil with nur behalten wird Verkettung, wenn der Wert mit dem Muster auf der linken Seite übereinstimmt. Wenn nicht, wird die Kette abgebrochen und das erste nicht übereinstimmende Ergebnis wird zurückgegeben. Zum Beispiel, wenn die Datei nicht existiert dann File.read(path) kehrt {:error, :enoent} - das ist nicht {:ok, binary} überein, so dass der with/1 Anruf kehrt {:error, :enoent}.

Es ist erwähnenswert, dass mit mit jedem Muster verwendet wird, nicht nur {:ok, foo} und {:error, reason} (obwohl es ist ein sehr häufiger Anwendungsfall).

+2

In der Tat sieht die "mit Version" viel besser aus. Dies ist sehr nützlich. – diogovk

+0

Ich denke, der Körper von 'defp read_chunks' sollte nur lesen ': beam_lib.chunks (binary,: abstract_code)' (dh ohne die anfängliche '{: ok,') – Grandpa

+0

Ich fühle mich wie ok_jose (https: // github. com/vic/ok_jose) sieht viel sauberer aus (abgesehen von dem Namen). Gibt es einen Grund, das nicht stattdessen zu verwenden? – Johannes

15

Sie können auch die Kette "bare Ausdrücke", wie der Doc sagt:

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

Die Variable header nur innerhalb der with Anweisung zur Verfügung stehen wird. Weitere Informationen unter https://gist.github.com/josevalim/8130b19eb62706e1ab37

2

Eine Sache zu erwähnen, können Sie when Schutz in with Anweisung verwenden. Zum Beispiel

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 , %{}})