首页 > Erlang并发教程 > 8.1 Erlang并发编程-Catch和Throw
2013
11-15

8.1 Erlang并发编程-Catch和Throw

Catch和Throw

catchthrow提供了一种表达式求值的监视机制,可以用于

  • 处理顺序代码中的错误(catch
  • 函数的非本地返回(catch结合throw

表达式求值失败(如一次匹配失败)的一般后果是导致求值进程的异常退出。通过以下方式可以借助catch来更改这个默认行为:

catch Expression

若表达式的求值过程没有发生错误,则catch Expression返回Expression的值。于是catch atom_to_list(abc)会返回[97,98,99]catch 22会返回22

若求值过程失败,catch Expression将返回元组{'EXIT', Reason},其中Reason是用于指明错误原因的原子式(参见第??节)。于是catch an_atom - 2会返回{'EXIT',badarith}catch atom_to_list(123)会返回{'EXIT', badarg}

函数执行结束后,控制流程便返还者。throw/1可以令控制流程跳过调用者。如果我们像上述的那样计算catch Expression,并在Expression的求值过程中调用throw/1,则控制流程将直接返回至catch。注意catch可以嵌套;在嵌套的情况下,一次失败或throw将返回至最近的catch处。在catch之外调用throw/1将导致运行时错误。

下面的例子描述了catchthrow的行为。定义函数foo/1

foo(1) ->
    hello;
foo(2) ->
    throw({myerror, abc});
foo(3) ->
    tuple_to_list(a);
foo(4) ->
    exit({myExit, 222}).

假设在不使用catch的情况下,一个进程标识为Pid的进程执行了这个函数,则:

foo(1)

返回hello

foo(2)

执行throw({myerror,abc})。由于不在catch的作用域内,执行foo(2)的进程将出错退出。

foo(3)

执行foo(3)的进程执行BIF tuple_to_list(a)。这个BIF用于将元组转换为列表。在这个例子中,参数不是元组,因此该进程将出错退出。

foo(4)

执行BIF exit/1。由于不在catch的范围内,执行foo(4)的函数将退出。很快我们就会看到参数{myExit,222}的用途。

foo(5)

执行foo(5)的进程将出错退出,因为函数foo/1的首部无法匹配foo(5)

现在让我们来看看在catch的作用域内对foo/1以相同的参数进行求值会发生什么:

demo(X) ->
    case catch foo(X) of
        {myerror, Args} ->
            {user_error, Args};
        {'EXIT', What} ->
            {caught_error, What};
        Other ->
            Other
    end.

demo(1)

像原来一样执行hello。因为没有任何失败发生,而我们也没有执行throw,所以catch直接返回foo(1)的求值结果。

demo(2)

求值结果为{user_error,abc}。对throw({myerror,abc})的求值导致外围的catch返回{myerror, abc}同时case语句返回{user_error,abc}

demo(3)

求值结果为{caught_error,badarg}foo(3)执行失败导致catch返回{'EXIT',badarg}

demo(4)

求值结果为{caught_error,{myexit,222}}

demo(5)

求值结果为{caught_error,function_clause}

注意,在catch的作用域内,借助{'EXIT', Message},你能够很容易地“伪造”一次失败——这是一个设计决策[1]


8.1 Erlang并发编程-Catch和Throw》有 2 条评论

  1. 这能开嘛*** 撞死算保险的***

  2. 这能开嘛*** 撞死算保险的***

留下一个回复

你的email不会被公开。