In elixer 1.2 hebben ze het trefwoord “met” opgenomen, maar het is mij niet helemaal duidelijk waarvoor het dient.
Hoe en in welke situatie zou ik het gebruiken?
Antwoord 1, autoriteit 100%
In versies van Elixir ouder dan 1.2, wanneer je functies in een pijplijn gebruikt, zou je ofwel een monad-bibliotheek moeten gebruiken of nest-case-statements (die zouden kunnen worden aangepast met behulp van privé-functies, maar toch uitgebreid zouden worden). with/1biedt een andere manier om dit probleem op te lossen.
Hier is een voorbeeld van het oorspronkelijke voorstel:
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 is hetzelfde aangepast om functies te gebruiken:
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
En dezelfde code met with
:
with {:ok, binary} <- File.read(path),
{:ok, data} <- :beam_lib.chunks(binary, :abstract_code),
do: {:ok, wrap(data)}
Dit werkt omdat with
alleen blijft ketenen als de waarde overeenkomt met het patroon aan de linkerkant. Zo niet, dan wordt de keten afgebroken en wordt het eerste niet-overeenkomende resultaat geretourneerd. Als het bestand bijvoorbeeld niet bestaat, zal File.read(path)
{:error, :enoent}
retourneren – dit komt niet overeen met {:ok, binary}
dus de with/1
aanroep retourneert {:error, :enoent}.
Het is vermeldenswaard dat with kan worden gebruikt met elk patroon, niet alleen {:ok, foo}
en {:error, reason}
(hoewel het een zeer veelvoorkomend gebruik).
Antwoord 2, autoriteit 22%
Je kunt ook “kale uitdrukkingen” koppelen, zoals de doc zegt:
with {:ok, binary} <- File.read(path),
header = parse_header(binary),
{:ok, data} <- :beam_lib.chunks(header, :abstract_code),
do: {:ok, wrap(data)}
De variabele header
is alleen beschikbaar binnen de with
-instructie. Meer info op https://gist.github.com/josevalim/8130b19eb62706e1ab37
Antwoord 3, autoriteit 5%
Eén ding om te vermelden is dat je when
guard in with
statement kunt gebruiken.
Bijvoorbeeld
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 , %{}})