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)指出,投掷和错误之间的重要区别,我略过了。此编辑仅用于记录

throw
error
用于在其他语言中使用
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}
    ,其中
    原因
    包含堆栈跟踪;而from
    exit/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>