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

Abh*_*k S 1 error-handling elixir

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

  1. 返回一个元组,例如File.open返回类似{:ok, io_device}或的东西{:error, posix}

  2. 提高例外,例如 File.open!

我的问题是:

  1. 有两种方式的意图是什么?
  2. 一个优先于另一个(如最佳实践)?

mic*_*ala 5

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

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

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

我会说元组样式是优越的,因为它控制了调用者 - 调用者可以通过case表达式中返回值的模式匹配和处理两种可能性来决定如何处理错误,或者忽略错误一,模式直接匹配ok元组.如果MatchError发生意外错误,第二个会将返回值转换为异常.您可以看到第一种样式如何轻松转换为第二种样式.也就是说,许多库提供"爆炸"功能,这些功能会增加错误,易于使用,并且能够提供比普通MatchError允许的更好的错误消息.

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

{value, rest} | :error
Run Code Online (Sandbox Code Playgroud)

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

string | :error
Run Code Online (Sandbox Code Playgroud)

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