探索を続けるwith文
2488 ワード
前のブログ「きれいなwith、魚と熊の掌を兼ねることができる」では、withの優雅さを示したが、
そのブログで、私はこう言いました.
結局with/1はtry/catchではなく、実行中に投げ出されたエラーをキャプチャしてelseに移行してエラー処理を行うことはできません.モードマッチングにエラーが発生した場合にのみelseに移行します.
エラーを優雅に処理し、優雅なwith/1で論理を直列に接続するにはget_を再構築する必要があります.user,get_response,send_responseなどの関数.プログラムロジックが正しい場合、tupleオブジェクト{:ok,result}を返します.エラーが発生した場合は{:error,error}を返します.
このような再構築が行われれば、
Joseph KainはブログLearning Elixir's withでectoクエリーを実行する例を示した.
業務にかかわらず、
余分なコードは効果的に消去され、機能と丈夫性は低下しなかった.これはwithinの奇妙なところです.
with
と|>
を比較すると、言葉が尽きず、説明が不十分だった.そのブログで、私はこう言いました.
結局with/1はtry/catchではなく、実行中に投げ出されたエラーをキャプチャしてelseに移行してエラー処理を行うことはできません.モードマッチングにエラーが発生した場合にのみelseに移行します.
エラーを優雅に処理し、優雅なwith/1で論理を直列に接続するにはget_を再構築する必要があります.user,get_response,send_responseなどの関数.プログラムロジックが正しい場合、tupleオブジェクト{:ok,result}を返します.エラーが発生した場合は{:error,error}を返します.
このような再構築が行われれば、
|>
も丈夫さと優雅さを結びつけることができることを意味するのだろうか.Elixirでは、関数の定義にパターンマッチングが用いられるため、|>
の動作に関与する関数を定義する際に、パターンマッチングによって様々な状況を考慮することができ、{:error, error}
の場合の処理を含んで、その関数を流れる際にエラーによってデータストリームがクラッシュしないようにすることができる.Joseph KainはブログLearning Elixir's withでectoクエリーを実行する例を示した.
defp results(conn, search_params) do
conn.assigns.current_user
|> Role.scope(can_view: Service)
|> within(search_params)
|> all
|> preload(:user)
end
defp within(query, %{"distance" => ""}), do: {:ok, query}
defp within(query, %{"distance" => x, "location" => l} do
{dist, _} = Float.parse(x)
Service.within(query, dist, :miles, l)
end
defp within(query, _), do: {:ok, query}
defp all({:error, _} = result), do: result
defp all({:ok, query}), do: {:ok, Repo.all(query)}
defp preload({:error, _} = result), do: result
defp preload({:ok, enum}, field) do
{:ok, Repo.preload(enum, field)}
end
業務にかかわらず、
all
およびpreload
関数において{:error, _}
分岐の処理が増加したことを明確に見ることができ、これにより、データフローのパイプラインがエラーによって終了することを回避することができる.with
を使用すると、|>
よりも構造が明瞭で直感的ではないが、all
およびpreload
におけるエラーブランチの処理を回避することができる.with
文は同様にパターンマッチングを使用するため、参加する方法がパターンマッチングの条件を満たすことができない限り、do
は実行されず、エラーによる終了を回避する.defp results(conn, search_params) do
with user ""}), do: {:ok, query}
defp within(query, %{"distance" => x, "location" => l} do
{dist, _} = Float.parse(x)
Service.within(query, dist, :miles, l)
end
defp within(query, _), do: {:ok, query}
defp all(query), do: Repo.all(query)
defp preload(enum, field) do: {:ok, Repo.preload(enum, field)}
all/1
およびpreload/2
は、Repo.all/1
およびRepo.preload/2
の単純パッケージにすぎないので、コードをさらに簡略化することができる.defp results(conn, search_params) do
with user
余分なコードは効果的に消去され、機能と丈夫性は低下しなかった.これはwithinの奇妙なところです.