Error handling 为什么在长生不老药中有两种表示错误的方法?
一些Elixir函数有两种变体用于指示错误Error handling 为什么在长生不老药中有两种表示错误的方法?,error-handling,elixir,Error Handling,Elixir,一些Elixir函数有两种变体用于指示错误 返回一个元组,例如File.open,它返回类似{:ok,io\u device}或{:error,posix} 引发异常,例如File.open 我的问题是: 有两种方式的目的是什么 一种方法是否优于另一种方法(如最佳实践) 有两种处理错误的方法,因为有两种类型的错误: 预期的错误-如用户提供错误数据等。在这种情况下,使用元组样式的返回值来处理错误。这也迫使调用方考虑错误情况并正确处理。 真正出乎意料的异常——比如配置文件突然消失,无法从中恢复,除
File.open
,它返回类似{:ok,io\u device}
或{:error,posix}
File.open代码>
有两种处理错误的方法,因为有两种类型的错误:
- 预期的错误-如用户提供错误数据等。在这种情况下,使用元组样式的返回值来处理错误。这也迫使调用方考虑错误情况并正确处理。
- 真正出乎意料的异常——比如配置文件突然消失,无法从中恢复,除了崩溃之外没什么可做的。在这种情况下,您将引发一个异常
case
表达式中的返回值进行模式匹配并处理这两种可能性,或者忽略错误的一种,直接对ok
元组进行模式匹配来决定如何处理错误。如果发生意外错误,第二个将把返回值转换为MatchError
异常。您可以看到如何轻松地将第一种样式转换为第二种样式。也就是说,许多库提供了“bang”函数,这些函数会引发错误,以便于使用,并且能够提供比普通的MatchError
所允许的更好的错误消息
虽然{:ok,value}
通常与{:error,reason}
成对出现,但这只是一种约定。有许多API只返回:error
而没有原因,原因很明显,也有一些API在成功的情况下返回不同的结果。这里的规则是提供一个不依赖顺序的简单模式匹配。让我们看一些例子:
{value, rest} | :error
这是一个很好的选择,因为案例很容易区分——例如,Integer.parse/2
使用这种样式。如果成功条件有两个返回值,并且失败原因只有一个,则建议使用此样式
string | :error
这似乎不是一个好主意,您要么需要在模式匹配中有一个防护装置,要么首先小心匹配
:error
atom。相反,可以将成功值包装在{:ok,string}
元组中以便于使用。有两种处理错误的方法,因为有两种类型的错误:
- 预期的错误-如用户提供错误数据等。在这种情况下,使用元组样式的返回值来处理错误。这也迫使调用方考虑错误情况并正确处理。
- 真正出乎意料的异常——比如配置文件突然消失,无法从中恢复,除了崩溃之外没什么可做的。在这种情况下,您将引发一个异常
case
表达式中的返回值进行模式匹配并处理这两种可能性,或者忽略错误的一种,直接对ok
元组进行模式匹配来决定如何处理错误。如果发生意外错误,第二个将把返回值转换为MatchError
异常。您可以看到如何轻松地将第一种样式转换为第二种样式。也就是说,许多库提供了“bang”函数,这些函数会引发错误,以便于使用,并且能够提供比普通的MatchError
所允许的更好的错误消息
虽然{:ok,value}
通常与{:error,reason}
成对出现,但这只是一种约定。有许多API只返回:error
而没有原因,原因很明显,也有一些API在成功的情况下返回不同的结果。这里的规则是提供一个不依赖顺序的简单模式匹配。让我们看一些例子:
{value, rest} | :error
这是一个很好的选择,因为案例很容易区分——例如,Integer.parse/2
使用这种样式。如果成功条件有两个返回值,并且失败原因只有一个,则建议使用此样式
string | :error
这似乎不是一个好主意,您要么需要在模式匹配中有一个防护装置,要么首先小心匹配:error
atom。相反,为了便于使用,可以将success值包装在{:ok,string}
元组中