【发布时间】:2017-03-19 19:18:56
【问题描述】:
一些 Elixir 函数有 2 个变体来指示错误
返回一个元组,例如
File.open返回类似{:ok, io_device}或{:error, posix}引发异常,例如
File.open!
我的问题是:
- 有两种方式的目的是什么?
- 其中一种是否优于另一种(如最佳实践)?
【问题讨论】:
标签: error-handling elixir
一些 Elixir 函数有 2 个变体来指示错误
返回一个元组,例如File.open 返回类似 {:ok, io_device} 或 {:error, posix}
引发异常,例如File.open!
我的问题是:
【问题讨论】:
标签: error-handling elixir
有两种处理错误的方法,因为有两种类型的错误:
由于这两种方式,您极少会发现自己需要挽救异常 - 在其他语言中您会挽救异常,而在 Elixir 中您一开始就避免引发异常,而是返回一个 ok/error 元组.
我会说元组样式更好,因为它可以控制调用者 - 调用者可以通过在 case 表达式中的返回值上进行模式匹配并处理这两种可能性来决定如何处理错误,或者,忽略错误的,直接在ok 元组上进行模式匹配。如果发生意外错误,第二个会将返回值转换为MatchError 异常。您可以看到第一种样式如何轻松转换为第二种样式。这就是说,许多库提供了引发错误的“爆炸”函数,以便于使用并且能够提供比普通 MatchError 所允许的更好的错误消息。
虽然{:ok, value} 通常与{:error, reason} 配对,但这只是一种约定。有很多 API 无缘无故只返回 :error,原因很明显,也有一些在成功的情况下返回不同的东西。这里的规则是提供一个不依赖于顺序的简单模式匹配。让我们看一些例子:
{value, rest} | :error
这是一个不错的选择,因为案例很容易区分 - 例如 Integer.parse/2 就使用了这种样式。如果成功条件有两个返回值,而失败的原因只有一个,建议使用这种样式。
string | :error
这似乎不是一个好主意,您要么需要在模式匹配中设置守卫,要么先小心匹配 :error 原子。相反,为了便于使用,可以将成功值包装在 {:ok, string} 元组中。
【讨论】: