Erlang 我应该使用退出、错误还是抛出?
您能告诉我什么时候使用Erlang 我应该使用退出、错误还是抛出?,erlang,Erlang,您能告诉我什么时候使用抛出,退出和错误 1>捕获抛出({aaa})。 {aaa} 2> 捕获出口({aaa})。 {'EXIT',{aaa} 3> 捕获genu服务器:调用(aaa,{aaa})。 {'EXIT',{noproc,{gen_server,call,[aaa,{aaa}]} 4> 捕获出口(“jaj”) {'EXIT','jaj} [更新] 罗伯特·维丁(Robert Virding)指出,投掷和错误之间的重要区别,我略过了。此编辑仅用于记录 throwerror用于在其他语言中使
抛出
,退出
和错误
1>捕获抛出({aaa})。
{aaa}
2> 捕获出口({aaa})。
{'EXIT',{aaa}
3> 捕获genu服务器:调用(aaa,{aaa})。
{'EXIT',{noproc,{gen_server,call,[aaa,{aaa}]}
4> 捕获出口(“jaj”)
{'EXIT','jaj}
[更新]
罗伯特·维丁(Robert Virding)指出,投掷和错误之间的重要区别,我略过了。此编辑仅用于记录
throwerror
用于在其他语言中使用throw
的地方。代码检测到正在运行的进程中存在错误,这表示出现异常,出现error/1
。同一进程捕获它(可能在堆栈的更高位置),错误将在同一进程中处理<代码>错误总是伴随着堆栈跟踪
throw
不用于表示错误,而仅用于从深度嵌套的函数返回值。
由于它展开堆栈,因此调用throw
将抛出的值返回到捕获它的位置。与error
一样,我们正在捕获抛出的内容,只是抛出的不是错误,而是传递到堆栈的值。这就是为什么throw不会带来stacktrace
作为一个人为的例子,如果我们想要为列表实现一个exists
函数(类似于list:any
所做的),并且作为一个练习,而不需要自己递归,只使用list:foreach
,那么可以在这里使用throw
:
exists(P, List) ->
F = fun(X) ->
case P(X) of
true -> throw(true);
Whatever -> Whatever
end
end,
try lists:foreach(F, List) of
ok -> false
catch
true -> true
end.
抛出但未捕获的值被视为错误
:将生成nocatch
异常
当进程“放弃”时,将发出退出信号。父进程处理退出,而子进程刚刚结束。这就是Erlang让它崩溃的哲学
因此,exit/1
的退出不会在同一进程中被捕获,而是留给父进程error/1
的错误是流程的局部错误,即发生了什么以及流程本身如何处理的问题<代码>抛出/1用于控制堆栈中的流
[更新]
exit/2
——用进程的Pid
调用以将退出发送到。
exit/1
表示父进程有3个类可以通过
try。。。捕获
:抛出
,错误
和退出
是使用throw
生成的,用于非本地返回,除非未捕获错误(当您收到throw/1
错误时),否则不会生成错误nocatch
在系统检测到错误时生成。您可以使用错误
显式生成错误。系统还在生成的错误值中包含堆栈跟踪,例如error/1
{badarg,[…]}
是使用exit
生成的,其目的是发出此过程即将结束的信号exit/1
error/1
和exit/1
之间的区别并不是很大,更多的是关于由错误生成的stacktrace增强的意图
在执行
catch…
时,它们之间的差异实际上更为明显:当使用throw/1
时,catch
只返回抛出的值,这是非本地返回的预期结果;当使用错误/1
时,捕获
返回{'EXIT',Reason}
,其中原因
包含堆栈跟踪;而fromexit/1
catch
也返回{'exit',Reason}
,但Reason
仅包含实际的退出原因<代码>尝试。。。catch看起来它等同于它们,但它们非常不同。我对Erlang是新手,但下面是我对这些东西的看法,它们的区别,它们的用途等等:
抛出
:应在本地(即在当前进程内)处理的条件。例如,调用方正在集合中查找元素,但不知道该集合是否实际包含此类元素;然后,如果这样的元素不存在,则被调用方可以抛出,调用方通过使用try[/of]/catch
检测缺席。若调用者忽略了这一点,那个么这将变成一个nocatch
错误(解释如下)
退出
:当前进程已完成。例如,它只是简单地完成了(在这种情况下,您将通过正常
,这与原始函数返回的处理相同),或者它的操作被取消(例如,它通常无限循环,但刚刚收到一条关闭
消息)
错误
:进程已经做了一些事情和/或达到了程序员没有考虑到的状态(例如1/0)、认为不可能的状态(例如
的的案例…遇到了与任何案例都不匹配的值),或者未满足某些先决条件(例如输入为非空)。在这种情况下,本地恢复没有意义。因此,throw
和exit
都不合适。由于这是意外的,堆栈跟踪是原因之一
如您所见,上面的列表是按升序排列的:
throw
用于要求调用方处理的正常情况。即在当前流程中进行处理
exit
也是正常的,但是应该仅仅因为流程已经完成就结束当前流程
错误
是疯狂的。发生了一些无法从中合理恢复的情况(通常是错误?),而本地恢复不会
serve_good_times() ->
receive
{top_of_the_mornin, Sender} ->
Sender ! and_the_rest_of_the_day_to_yourself;
{you_suck, Sender} ->
Sender ! take_a_chill_pill;
% More cases...
shut_down ->
exit(normal)
end,
serve_good_times()
end
1> self().
<0.32.0>
2> spawn_link(fun() -> exit(normal) end).
<0.35.0>
3> self().
<0.32.0>
4>
4>
4> spawn_link(fun() -> exit(abnormal) end).
** exception exit: abnormal
5> self().
<0.39.0>
6>
6> process_flag(trap_exit, true).
false
7> spawn_link(fun() -> exit(normal) end).
<0.43.0>
8> self().
<0.39.0>
9> flush().
Shell got {'EXIT',<0.43.0>,normal}
ok
10>
10>
10> spawn_link(fun() -> exit(abnormal) end).
<0.47.0>
11> self().
<0.39.0>
12> flush().
Shell got {'EXIT',<0.47.0>,abnormal}
13> spawn_link(fun() -> ok end).
<0.51.0>
14> flush().
Shell got {'EXIT',<0.51.0>,normal}
ok
15> self().
<0.39.0>