Erlang - 异常


任何编程语言都需要异常处理来处理运行时错误,以便维持应用程序的正常流程。异常通常会破坏应用程序的正常流程,这就是我们需要在应用程序中使用异常处理的原因。

通常,当Erlang发生异常或错误时,会显示以下消息。

{"init terminating in do_boot", {undef,[{helloworld,start,[],[]}, 
{init,start_it,1,[]},{init,start_em,1,[]}]}}

故障转储将被写入 -

erl_crash.dump
init terminating in do_boot ()

在 Erlang 中,有 3 种类型的异常 -

  • 错误- 调用erlang:error(Reason)将结束当前进程中的执行,并在捕获它时包含最后调用的函数及其参数的堆栈跟踪。这些是引发上述运行时错误的异常类型。

  • 存在- 有两种出口:“内部”出口和“外部”出口。内部退出是通过调用函数exit/1触发的,使当前进程停止执行。外部出口用exit/2调用,并且与 Erlang 并发方面的多个进程有关。

  • Throw - 抛出是一类异常,用于程序员可以处理的情况。与退出和错误相比,它们实际上并没有带来任何“进程崩溃!” 他们背后有意图,但他们控制着流程。当您在使用抛出并期望程序员处理它们时,通常最好在使用它们的模块中记录它们的使用情况。

try ... catch是一种计算表达式的方法,同时让您可以处理成功的情况以及遇到的错误。

try catch 表达式的一般语法如下。

句法

try Expression of 
SuccessfulPattern1 [Guards] -> 
Expression1; 
SuccessfulPattern2 [Guards] -> 
Expression2 

catch 
TypeOfError:ExceptionPattern1 -> 
Expression3; 
TypeOfError:ExceptionPattern2 -> 
Expression4 
end

try 和 of之间的表达式据说是受保护的。这意味着该调用中发生的任何类型的异常都将被捕获。try ... of 和 catch之间的模式和表达式的Behave方式与case ... of完全相同。

最后是 catch 部分——在这里,对于我们在本章中看到的每种类型,您可以将TypeOfError替换为错误、抛出或退出。如果未提供类型,则假定抛出异常。

以下是 Erlang 中的一些错误和错误原因 -

错误 错误类型
巴达格 不好的论点。参数的数据类型错误,或者格式错误。
巴达里斯 算术表达式中的参数错误。
{不匹配,V} 匹配表达式求值失败。值 V 不匹配。
函数子句 评估函数调用时未找到匹配的函数子句。
{case_clause,V} 评估 case 表达式时未找到匹配的分支。值 V 不匹配。
if_子句 计算 if 表达式时未找到真正的分支。
{try_子句,V} 评估 try 表达式的 of 部分时未找到匹配的分支。值 V 不匹配。
未定义 评估函数调用时找不到该函数。
{坏有趣,F} 有趣的 F 出了问题
{恶毒,F} 乐趣应用于错误数量的参数。F描述了乐趣和争论。
超时值 receive..after 表达式中的超时值被计算为整数或无穷大以外的值。
诺普克 尝试链接到不存在的进程。

以下是如何使用这些异常以及如何完成操作的示例。

  • 第一个函数生成所有可能的异常类型。

  • 然后我们编写一个包装函数来在 try...catch 表达式中调用generate_exception 。

例子

-module(helloworld). 
-compile(export_all). 

generate_exception(1) -> a; 
generate_exception(2) -> throw(a); 
generate_exception(3) -> exit(a); 
generate_exception(4) -> {'EXIT', a}; 
generate_exception(5) -> erlang:error(a). 

demo1() -> 
   [catcher(I) || I <- [1,2,3,4,5]]. 
catcher(N) -> 
   try generate_exception(N) of 
      Val -> {N, normal, Val} 
   catch 
      throw:X -> {N, caught, thrown, X}; 
      exit:X -> {N, caught, exited, X}; 
      error:X -> {N, caught, error, X} 
   end. 
      
demo2() -> 
   [{I, (catch generate_exception(I))} || I <- [1,2,3,4,5]]. 
demo3() -> 
   try generate_exception(5) 
   catch 
      error:X -> 
         {X, erlang:get_stacktrace()} 
   end. 
   
lookup(N) -> 
   case(N) of 
      1 -> {'EXIT', a}; 
      2 -> exit(a) 
   end.

如果我们将程序运Behave helloworld:demo()。,我们将得到以下输出 -

输出

[{1,normal,a},
{2,caught,thrown,a},
{3,caught,exited,a},
{4,normal,{'EXIT',a}},
{5,caught,error,a}]