Elixir中的try/rescue
和try/catch
都是错误处理技术。根据介绍指南中的corresponding chapter。
使用
可以挽救错误try/rescue
构造
另一方面,
throw
和catch
保留用于无法检索值的情况,除非使用throw
和catch
。
我简要了解rescue
是出错的。虽然catch
适用于任何值。
然而,
throw
和catch
',否则无法检索值的情况究竟是什么?答案 0 :(得分:20)
这是一个很好的问题。经过一番研究。
它们之间的细节有何不同?
José的回答:
主要是,您应该使用
throw
来控制流,并保留raise
来解决错误,这些错误会发生在开发人员的错误或特殊情况下。在Elixir中,这种区别相当理论化,但它们很重要 一些语言,如Ruby,使用错误/异常 控制流是昂贵的,因为创建异常对象和 回溯很昂贵。
请检查此回答Which situations require throw catch in Elixir
不久:
raise/rescue
考虑使用raise / rescue来明确地处理异常处理(程序员错误,错误环境等一些意外情况)。
throw/catch
在预期失败的地方很有用。 经典的例子是:
最后一个:
假设您正在尝试运行由Supervisor
监督的流程中的某些代码,但该流程会因意外原因而死亡。
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
然后你可以在这里使用catch异常:
try do
IO.inspect MayRaiseGenServer.maybe_will_raise
catch
:exit, _ -> IO.puts "there was an error"
end
好的。希望能够澄清我们正在寻找的东西。
答案 1 :(得分:7)
其他答案已涵盖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
(用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
请注意处理raise
和error
与rescue
与catch/2
的{{1}}的不对称性:x
包含在{{{ 1}}使用%ErlangError
但不使用rescue
。
答案 2 :(得分:1)
通过阅读Dimagog的答案以及在https://inquisitivedeveloper.com/lwm-elixir-48/上找到的文章,我确实获得了很多关于此问题的见识。我只是分享一个个人的实际例子,
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';
答案 3 :(得分:1)
我喜欢用这个比喻:
您要么catch
扔了球,要么rescue
来自山上的人。
catch
-是预期的并用于控制流(例如,类似Java的错误处理)rescue
-发生意外错误(例如运行时错误)答案 4 :(得分:0)
try/catch
必须在已知错误(例如请求验证错误)时使用,而 raise/rescue
必须用于捕获异常(异常是未知或未处理的错误)。
可以结合使用这两者。例如,
def example(conn, params) do
try do
data = %{}
types = %{field1: :string, field2: :integer}
changeset =
{data, types}
|> cast(params, [:field1, :field2])
|> validate_required([:field1, :field2])
if (!changeset.valid?) do
throw({:ClientError, changeset.errors })
end
# some logic
raise ArgumentError
catch
# client error is caught here
{:ClientError, error} ->
IO.inspect(error, label: "client error")
rescue
exception ->
# Argument error is caught here
IO.inspect(exception, label: "exception")
end
end