为什么在Elixir中有两种表示错误的方法?

时间:2016-11-06 10:41:33

标签: error-handling elixir

某些Elixir函数有2个变量用于指示错误

  1. 返回一个元组,例如File.open返回{:ok, io_device}{:error, posix}

  2. 之类的内容
  3. 提出异常,例如File.open!

  4. 我的问题是:

    1. 有两种方式的目的是什么?
    2. 是否优先于其他(如最佳做法)?

1 个答案:

答案 0 :(得分:5)

有两种处理错误的方法,因为有两种类型的错误:

  • 预期的错误 - 比如用户提供错误的数据等。在这种情况下,您使用元组样式的返回值来处理错误。这也会强制调用者考虑错误情况并正确处理它。
  • 真正意想不到的异常 - 就像配置文件突然消失一样,无法恢复,除了崩溃之外没什么可做的。在这种情况下,你提出了一个例外。

由于这两种方式,你很少发现自己需要拯救异常 - 在其他语言中你会拯救一个异常,在Elixir你首先避免提出异常,而是返回一个ok / error元组而不是

我说元组样式是优越的,因为它控制了调用者 - 调用者可以通过case表达式中返回值的模式匹配来决定如何处理错误处理这两种可能性,或者忽略错误的一种,直接在ok元组上进行模式匹配。如果发生意外错误,第二个会将返回值转换为MatchError异常。您可以看到第一种样式如何轻松转换为第二种样式。这就是说许多图书馆提供了#b; bang"与简单MatchError允许相比,提高错误以便于使用和提供更好的错误消息的函数。

虽然{:ok, value}经常与{:error, reason}配对,但它仅仅是一种约定。有许多API只返回:error没有理由,其中原因很明显,还有一些在成功案例中返回了一些不同的东西。这里的规则是提供一种不依赖于顺序的简单模式匹配。让我们看一些例子:

{value, rest} | :error

这是一个不错的选择,因为案例很容易区分 - 例如Integer.parse/2使用这种风格。如果成功条件有两个返回值,并且只有一个失败原因,建议使用此样式。

string | :error

这似乎不是一个好主意,你要么需要在模式匹配中有一个守卫,要么小心首先匹配:error原子。相反,为了便于使用,可以将成功值包装在{:ok, string}元组中。