Elixir 长生不老药-尝试/捕捉vs尝试/拯救? 背景
Elixir 长生不老药-尝试/捕捉vs尝试/拯救? 背景,elixir,Elixir,try/rescue和try/catch都是Elixir中的错误处理技术。根据介绍指南中的说明 可以使用try/rescue构造来挽救错误 另一方面, throw和catch保留用于无法检索值的情况,除非使用throw和catch 怀疑 我有一个简单的理解,rescue是针对错误的。而catch用于任何值 但是, 什么时候应该使用Elixir中的错误处理机制 它们在细节上有什么区别 我应该如何选择一个在特定用例中使用 “除非使用throw和catch,否则无法检索值的情况”到底是什么 这是一个
try/rescue
和try/catch
都是Elixir中的错误处理技术。根据介绍指南中的说明
可以使用try/rescue
构造来挽救错误
另一方面,
throw
和catch
保留用于无法检索值的情况,除非使用throw
和catch
怀疑
我有一个简单的理解,rescue
是针对错误的。而catch
用于任何值
但是,
- 什么时候应该使用Elixir中的错误处理机制
- 它们在细节上有什么区别
- 我应该如何选择一个在特定用例中使用
- “除非使用
和throw
,否则无法检索值的情况”到底是什么catch
- 他们在细节上有什么不同 何塞的回答是:
- 这是一个好问题。经过一点研究
throw
来控制流,并保留raise
来处理错误,这些错误发生在开发人员错误或异常情况下
在《长生不老药》中,这一区别相当理论化,但它们在理论上很重要
一些语言,如Ruby,其中使用错误/异常
由于创建异常对象和
回溯是昂贵的
- 我应该如何选择一个在特定用例中使用
升起/救援
考虑raise/rescue是关于异常处理的(一些意外情况,如程序员错误、错误环境等)
throw/catch
在您预期会失败的地方非常有用。
典型的例子有:
- 正在退出深度嵌套的递归调用:
- 正常错误处理成本太高(可能发生在太多 地点:
- 您有一个非本地构造(如事务):
- “除非使用抛出和捕获,否则无法检索值的情况”到底是什么
主管监督的进程运行某些代码,但该进程由于意外原因而死亡
try do
IO.inspect MayRaiseGenServer.maybe_will_raise
rescue
RuntimeError -> IO.puts "there was an error"
end
MayRaiseGenServer
由Supervisor
监督,由于某种原因引发了错误:
try do
IO.inspect MayRaiseGenServer.maybe_will_raise # <- Code after this line is no longer executed
好的。希望这能充分说明我们在寻找什么。其他答案已经涵盖了raise
与throw
的用法
我将描述如何使用表格处理每个异常情况的机制:
creating | handling with | where y is
-----------------------------------------------------
raise x | rescue y | %RuntimeError{message: x}
error(x) | rescue y | %ErlangError{original: x}
throw x | catch y | x
exit(x) | catch :exit, y | x
其中error(x)
实际上是:erlang.error(x)
除此之外,rescue
和catch/1
(catch-with-1参数)都只是一个语法糖。上述4种情况均可通过catch/2
处理:
creating | handling with | where y is | and z is
-----------------------------------------------------------------
raise x | catch y, z | :error | %RuntimeError{message: x}
error(x) | catch y, z | :error | x
throw x | catch y, z | :throw | x
exit(x) | catch y, z | :exit | x
注意rescue
与catch/2
处理raise
和error
的不对称性:x
在使用rescue
时被包装在%ErlangError
中,但通过阅读Dimagog的答案,在,在这件事上我真的获得了很多见解。我只是分享一个个人的实际例子
chset =
%SomeModel{}
|> SomeModel.changeset(attrs)
try do
chset
|> Repo.insert()
catch :error, %Postgrex.Error{postgres: %{code: :invalid_password}} ->
{ :error ,
chset
|> Changeset.add_error(:username, "may be invalid")
|> Changeset.add_error(:password, "may be invalid")
}
else
{:ok, lr} -> {:ok, Map.put(lr, :password, nil)}
error -> error
end
postgresql错误代码来自一个plpgsql
函数,我在该函数中引发了一个错误,如下所示:
raise invalid_password using
message = 'Invalid username or password' ,
detail = 'A user could not be found that matched the supplied username and password';
我喜欢用这个比喻:
您可以接住投出的球,或者从山上营救某人
catch
-预计用于控制流(例如类似Java的错误处理)
rescue
-针对意外错误(例如运行时错误)
您根本不应该使用它们;)您不想尝试/捕获所有错误的Java。当出现错误时,你应该使用监督员使你的应用程序健壮,或者在出现错误时使用raise。除了可接受的答案外,表中的可能重复项非常好。显示所有案例的表非常棒。我一直对援救/捕获以及您可以使用catch/1或catch/2感到困惑。这就清楚了。谢谢是的,这确实是一个很好而且非常简洁的回答。谢谢这张桌子很有用。我认为官方指南中关于这个话题的章节相当混乱。重要的一点是,一切都可以归结为catch/2
。它帮助我处理在数据库中引发的异常。
raise invalid_password using
message = 'Invalid username or password' ,
detail = 'A user could not be found that matched the supplied username and password';