我对erlang中的错误处理有一些概念性的问题。举个例子,我们可以使用一些返回{ok, Result}
或{error, Err}
的数据库调用。我有一个库包装调用这个数据库,所以我可以做一些前/后处理。当这个库调用数据库时,它应该执行
A)严重崩溃,否则返回结果:
{ok, Result} = db:call(), postprocess(Result).
B)严重崩溃,否则返回包装结果:
{ok, Result} = db:call(), {ok, postprocess(Result)}.
C)实际处理错误并将其返回:
case db:call() of
{ok, Result} -> {ok, postprocess(Result)};
{error, Err} -> {error, Err}
end.
D)其他东西
作为一个后续问题,如果我有另一个调用此库的库,它使用什么错误传播?我的想法是图书馆应该与其回归价值保持一致,我只是不清楚如何决定这些应该是什么。
答案 0 :(得分:1)
嗯,这取决于错误的类型以及应该如何处理。
B)
似乎最不可能在任何地方使用。由于您无法返回任何错误值,因此将它包装在ok
元组中是没有意义的。
A)
似乎是数据库连接库的一个很好的例子。例如,您可能会遇到与数据库连接的问题。通常,您不希望每次有人调用您的代码来预测此类情况,并重新启动服务器。 erlang方式是让用户崩溃,并让它的主管在良好的环境中重新启动它,并重做请求。这种方法允许用户端的快乐路径编码,以及应用程序逻辑和负责设置(并以相同方式重新启动)wright环境的代码之间的强大分离。
使用C)
方法可以实现类似的结果(客户端仅匹配ok
元组),但坚持A)
可能会让用户更多地了解您的方面会发生什么
当库客户端可以完全挖掘(从逻辑点)处理错误时,可以使用C)
处理。好的示例可能是proplist:get_value/2
,您可以在{Key, Value}
响应中模式匹配,也可以获得一个原子undefined
。返回没有ok
个原子,但Key
足以找到快乐的路径。通常,此代码的客户端可以轻松处理undefined
(这是一种错误),以完全挖掘其逻辑的方式。当然,他们只能在快乐的道路上进行模式匹配,并让它发挥作用。这个想法不仅仅是为了处理错误而处理错误;你只实现你的应用案例。
再说一遍。在C)
示例中,您只允许处理{error, Error}
个错误。如果您想传递所有错误,这可能是更好的方法:
case db:call() of
{ok, Result} ->
{ok, postprocess(Result)};
Else ->
Else
end.