《Learn You Some Erlang for Great Good!》的学习笔记(八)

     目前为止,我们并没有过多的牵扯到erlang中的错误处理机制,这是由于Erlang中主要包含两个主要方面:函数和并发;目前为止,我们都是介绍的函数的内容,而对于并发(actors, 成千上万的并发进程,监察树等)的内容并未展开;虽然函数中有很多处理错误的方法,但是如之前提到的,erlang鼓励你”let it crash”,而错误处理机制很多是在并发中使用到的。但是本章我们还是主要围绕函数中的错误处理,以期平滑地过渡到并发的内容。

异常分类

错误的分类主要有分为以下几种:

  • 编译时错误(相信不难理解,也就不一一罗列了)
  • 逻辑错误(此处有点废话了)
  • 运行时错误(这才是关键啊)

    • Function Clause Errors:这种错误主要是由于没有满足所有的guards语句而造成的,如下:
    1> lists:sort([3,2,1]).

    [1,2,3]

    2> lists:sort(fffffff).

    ** exception error: no function clause matching lists:sort(fffffff) (lists.erl, line 414) 
    • Case Caluse Errors: 和上面类似,当没有满足符合条件的Case时抛出
    • If Clause Errors: 当if语句没有指定true时抛出
    • Bad Match Errors: 当模式匹配失败的时候会抛出,如

      5> [X,Y] = {4,5}.
** exception error: no match of right hand side value {4,5}  
    • Bad Argument Errors:和Function Clause Errors类似,但一般是程序员自己抛出的

    • Undefined Function Errors: 一般是未从module中找到相应的方法所导致
    • Bad Arithmetic Errors: 除0或者atom于数字相加等都会导致

      8> 5 + llama.

      ** exception error: bad argument 
      in an arithmetic expression in operator  +/2 called as 5 + llama
    • Bad Function Errors: 这个最常见的是将变量作为函数使用时

    • Bad Arity Errors: 这个主要发生在高阶函数中,当函数调用时的入参数目大于实际定义的入参数目时抛出,如下:

      10> F = fun(_) -> ok end.
      
#Fun<erl_eval.6.13229925>

      
11> F(a,b).
      

** exception error: interpreted function with arity 1 called with two arguments
    • System Limit Errors: 这个比较宽泛了,涉及到进程过多、原子过长、函数入参过多、原子过多、链接节点过多等。

异常抛出

erlang中的异常主要有三种:errors, exists and throws.

  • Error异常:Errors的抛出很简单,只需要调用erlang:error(Reason)即可,他就会终止你当前的进程并打印出错误栈,注意,这属于运行时异常,仅当你无法预期处理结果时抛出。
  • Exit异常:Exit主要分为内部和外部exit。内部exit只需要调用exit/1就会退出当前进程,外部exit是调用exit/2,主要是用来处理多进程并发,外部退出将在之后多进程中介绍。实际上内部exit和error基本一致,区别就在于当进程结束时,会发送退出信号给其它监听进程,当使用error时,会讲错误栈等一起发送过去,而exit/1则不会。
  • Throw异常:Throw异常主要是用户程序员处理的异常,调用方法也很简单,使用throw/1方法即可。通常也可以用来中断递归的调用(类似于java中的break)。

异常的处理

try Expression of 
SuccessfulPattern1 [Guards] -> Expression1; 
SuccessfulPattern2 [Guards] -> Expression2 
catchTypeOfError:ExceptionPattern1 -> Expression3; 
TypeOfError:ExceptionPattern2 -> Expression4 
after
    Expression5
end.


异常处理的基本语法如上所示,其中after就相当于java中的finally,在此就不赘述了。我们可以定义一个函数来进行各种异常的试验,如下所示:

sword(1) -> throw(slice);
sword(2) -> erlang:error(cut_arm);
sword(3) -> exit(cut_leg);
sword(4) -> throw(punch);
sword(5) -> exit(cross_bridge).
black_knight(Attack) when is_function(Attack, 0) ->
    try Attack() of
        _ -> "None shall pass."
    catch
        throw:slice -> "It is but a scratch.";
        error:cut_arm -> "I've had worse.";
        exit:cut_leg -> "Come on you pansy!";
        _:_ -> "Just a flesh wound."
end.

talk() -> "blah blah".

试验过程及结果如下所示,一目了然:

7> c(exceptions).

{ok,exceptions}

8> exceptions:talk().

"blah blah"9> exceptions:black_knight(fun exceptions:talk/0).

"None shall pass."10> exceptions:black_knight(fun() -> exceptions:sword(1) end). 
"It is but a scratch."11> exceptions:black_knight(fun() -> exceptions:sword(2) end). 
"I've had worse."12> exceptions:black_knight(fun() -> exceptions:sword(3) end). 
"Come on you pansy!"13> exceptions:black_knight(fun() -> exceptions:sword(4) end). 
"Just a flesh wound."14> exceptions:black_knight(fun() -> exceptions:sword(5) end). 
"Just a flesh wound." 

对于想在try中执行多条语句的,也十分简单,只需要用都好隔开即可

whoa() -> try 
        talk(),
        _Knight = "None shall pass!",
        _Doubles = [N*2 || N <- lists:seq(1,100)],
        throw(up),
        _WillReturnThis = tequila
    of
        tequila -> "Hey, this worked!"
    catch
        Exception:Reason -> {caught, Exception, Reason}
end. 
发布了42 篇原创文章 · 获赞 9 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/jjxojm/article/details/52605478