通常,我的代码使用with
宏来确保在继续操作之前所有必需的数据都可用,但是我希望有更多细粒度的错误来准确确定其失败原因。
使用文档中的示例:
with {:ok, width} <- Map.fetch(opts, :width),
{:ok, height} <- Map.fetch(opts, :height) do
{:ok, width * height}
else
:error ->
{:error, :wrong_data}
end
我想知道错误元组中是否缺少width
或height
。
我试图使用默认值:
with {:ok, width} <- Map.fetch(opts, :width, {:error, :missing_width}),
{:ok, height} <- Map.fetch(opts, :height, {:error, :missing_height}) do
{:ok, width * height}
else
{:error, reason} = error -> error
end
但这并不特别优雅。有没有更惯用的方式?
答案 0 :(得分:5)
您可以将with
行包裹在描述性元组上,并仍然在所需的返回值上断言,这将使您可以识别/提供错误所在的反馈。
with(
{_, {:ok, width}} <- {:width, Map.fetch(opts, :width)},
{_, {:ok, height}} <- {:height, Map.fetch(opts, :height)}
) do
{:ok, width * height}
else
{what, :error} ->
{:error, {what, :wrong_data}}
end
答案 1 :(得分:0)
这可能与您提供的示例有关,但是您始终可以创建包装器模块/函数。
defmodule MapHelpers do
def fetch_number(%{} = map, field) do
case Map.fetch(map, field) do
{:ok, val} when is_number(val) ->
{:ok, val}
{:ok, val} ->
{:error, "#{to_string(val)} in attribute #{to_string(field)} is not a number"}
:error ->
{:error, "#{to_string(field)} is not defined"}
end
end
end
然后,您在其他地方的代码将变得更加简单:
with {:ok, width} <- MapHelpers.fetch_number(opts, :width),
{:ok, height} <- MapHelpers.fetch_number(opts, :height) do
{:ok, width * height}
end
通过这种方式,您不必定义else块,并且具有可重用的代码来从地图中提取数字。