什么时候在Erlang中使用throw/1 vs. exit/1 vs. error/1?

Che*_* Yu 8 erlang

今天为了捕获错误问题,我已阅读erlang's错误和错误处理文档.

对于生成的错误类型,有两种类型,一种是exit,另一种是throw.在点击我的源代码之后,throw and exit表达式已经集中了.

两者都相似,似乎只是捕捉匹配表达是不同的.

(emacs@chen-yumatoMacBook-Pro.local)30> catch throw ({aaa}).
{aaa}
(emacs@chen-yumatoMacBook-Pro.local)31> catch exit ({aaa}).
{'EXIT',{aaa}}
(emacs@chen-yumatoMacBook-Pro.local)32> catch gen_server:call(aaa,{aaa}).
{'EXIT',{noproc,{gen_server,call,[aaa,{aaa}]}}}
Run Code Online (Sandbox Code Playgroud)

你能告诉我什么时候使用throw以及何时使用exit?

rvi*_*ing 16

3类,可以用被捕获try ... catch:throw,errorexit.

  • throw是生成使用throw/1并且旨在用于非本地返回,并且除非未捕获(当您收到nocatch错误时),否则不会生成错误.

  • error系统检测到错误时生成.您可以使用显式生成错误error/1.例如,系统还包括生成的错误值中的堆栈跟踪{badarg,[...]}.

  • exit使用exit/1并且意图表示该过程将死亡.

error/1和之间的区别exit/1不是那么大,它更多的是由错误产生的堆栈跟踪增强的意图.

实际上,它们之间的区别实际上更明显catch ...:当throw/1使用when时,catchjust返回抛出的值,正如非本地返回所期望的那样; 当error/1被使用,则在catch返回{'EXIT',Reason}其中Reason包含堆栈跟踪; 而from exit/1 catch也返回,{'EXIT',Reason}Reason只包含实际的退出原因.try ... catch看起来它等同于他们,但他们是非常不同的.


Fai*_*aiz 6

[更新]

Robert Virding指出,我忽略了抛出错误之间的重要区别.此编辑仅供记录!

throw error将用于throw其他语言中使用的地方.您的代码检测到正在运行的进程中的错误,该错误表示异常error/1.相同的进程捕获它(可能在堆栈中更高),并且错误将在同一进程中处理.error总是带来一个堆栈跟踪.

throw用于不发出错误信号,而只是从深层嵌套函数返回一个值.由于它展开堆栈,因此调用throw将抛出的值返回到捕获的位置.就像在这种情况下一样error,我们正在捕获抛出的东西,只有被抛出的东西不是错误,而只是一个值传递给堆栈的值.这就是为什么throw不会带来堆栈跟踪的原因.

作为一个人为的例子,如果我们想要exists为列表实现一个函数(类似于那个list:any),并且作为一个练习没有自己进行递归,并使用just 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.
Run Code Online (Sandbox Code Playgroud)

抛出但未捕获的值被视为error:nocatch将生成异常.

EXIT将在"放弃"时由进程发出信号.在进程处理退出,而孩子只是过程死亡.这是Erlang let-it-crash理念.

因此exit/1,EXIT不会被捕获在同一个过程中,而是留给父母.error/1错误是过程的本地错误 - 即,过程本身发生了什么以及如何处理错误; throw/1用于跨越堆栈的控制流.

[UPDATE]

  1. 本教程很好地解释了它:http://learnyousomeerlang.com/errors-and-exceptions
  2. 注意还有一个exit/2- 用Pid一个进程发送EXIT来调用. exit/1暗示父进程.