Home > Erlang探索 > 对try 异常 运行的疑问,为什么出现两种结果

对try 异常 运行的疑问,为什么出现两种结果

April 5th, 2010

原创文章,转载请注明: 转载自系统技术非业余研究

本文链接地址: 对try 异常 运行的疑问,为什么出现两种结果

郎咸武<langxianzhe@163.com>  同学在erlang-china上post了一个问题:
请注意编号为91和92两行运行结果,请问为什么会出现两种结果。
一个抛出 {error,{badmatch,5}}
另一个抛出** exception error: no match of right hand side value 4

root@ubuntu:/usr/src/otp# erl
Erlang R13B04 (erts-5.7.5) [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false
88> X=1.
1
89> try (X=5) of Val ->{normal,Val} catch error:Error -> {error,Error}  end.
{error,{badmatch,5}}
90> try (X=1) of Val ->{normal,Val} catch error:Error -> {error,Error}  end.
{normal,1}
91> try (X=5) of Val ->{normal,Val} catch error:Error -> {error,Error}  end.
{error,{badmatch,5}}
92> try (X=4) of Val ->{normal,Val} catch error:Error -> {error,Error}  end.
** exception error: no match of right hand side value 4
93> self().
<0.36.0>
94> catch try (X=4) of Val  ->{normal,Val} catch error:Error -> {error,Error}  end. %%这个异常是 shell捕获到了 进一步处理后的结果
{'EXIT',{{badmatch,4},[{erl_eval,expr,3}]}}
95> try (X=4) of Val ->{normal,Val} catch error:Error ->  {error,Error}  end.
** exception error: no match of right hand  side value 4
96> self().
<0.36.0>

竟然是EXIT, 这时候shell也换了pid了, 这是怎么回事呢?
由于在shell输入的程序是公司允许的, 我们也可以从出错的stack里面看到是 erl_eval:expr函数异常了.
现在让我们对系统打patch如下:
lib/stdlib/src/erl_eval.erl

 282expr({match,_,Lhs,Rhs0},  Bs0, Lf, Ef, RBs) ->
 283    {value,Rhs,Bs1} = expr(Rhs0, Bs0,  Lf, Ef, none),
 284    case match(Lhs, Rhs, Bs1) of
 285         {match,Bs} ->
 286            ret_expr(Rhs, Bs, RBs);
 287        nomatch ->
 288            io:format("expr nomatch->pid:~p~n~p~n",[self(), Rhs]),   %%添加诊断
 289             erlang:raise(error, {badmatch,Rhs}, stacktrace())
 290    end;

erts/emulator/beam/bif.c

1142/**********************************************************************/
1143/*  raise an exception of given class, value and  stacktrace.
1144  *
1145 * If there is an error in the argument  format,
1146 * return the atom 'badarg'  instead.
1147 */
1148Eterm
1149raise_3(Process *c_p, Eterm class,  Eterm value, Eterm stacktrace) {
...
1222     erts_print(ERTS_PRINT_STDOUT, NULL, "raise->proc:%T\nclass=%T\nvalue=%T\nstacktrace=%T\n", c_p->id, class, value,  c_p->ftrace); /*添加诊断*/
1223    BIF_ERROR(c_p, reason);
...
}

然 后我们在运行上面的语句:

root@ubuntu:~/otp#  bin/erl
Erlang R13B04 (erts-5.7.5) [source]  [smp:2:2] [rq:2]  [async-threads:0] [kernel-poll:false]

Eshell  V5.7.5  (abort with  ^G)
1> X=1.
 1
2>  try (X=5) of Val ->{normal,Val}  catch error:Error ->  {error,Error}  end.
expr nomatch->pid:<0.32.0>
5
raise->proc:<0.32.0>
class=error
value={badmatch,5}
stacktrace=[[{erl_eval,expr,3}
{error,{badmatch,5}}
3>  try  (X=4) of Val ->{normal,Val} catch  error:Error -> {error,Error}   end.
expr nomatch->pid:<0.32.0>
4
raise->proc:<0.32.0>
class=error
value={badmatch,4}
stacktrace=[[{erl_eval,expr,3}]|-000000000000000016]
raise->proc:<0.32.0>
class=error
value={badmatch,4}
stacktrace=[[{erl_eval,expr,3}]|-000000000000000016]

很奇怪的是第3句raise了2次. 让我们回到程序好好看下:

X=1.   %%这行绑定了一个变量X=1
try (X=5) of Val ->{normal,Val} catch  error:Error -> {error,Error}  end.   %%这行由于异常会试图绑定变量Error={badmatch,5}, 由于之前Error不存在, 绑定成功.
try  (X=4) of Val ->{normal,Val} catch error:Error -> {error,Error}   end.   %%这行由于异常会绑定了变量Error={badmatch,4}, 由于Error存在,  而且值是{badmatch,5},所以这时候catch就出
现异常了,  往外抛出{'EXIT',{{badmatch,4},[{erl_eval,expr,3}]}}.

这 下我们明白了, 是这个catch惹的祸了.
我们再实验下我们的分析:

root@ubuntu:~#  erl
Erlang R13B04 (erts-5.7.5) [source] [smp:2:2] [rq:2]  [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.7.5   (abort with ^G)
1> X=1.
1
2> b().
X = 1
ok
3>  try (X=5) of Val ->{normal,Val} catch error:Error ->  {error,Error}  end.
{error,{badmatch,5}}
4> b().
Error =  {badmatch,5}
X = 1
ok
5> try (X=4) of Val ->{normal,Val}  catch error:Error -> {error,Error}  end.
** exception error: no  match of right hand side value 4
6> f(Error).
ok
7>  b().
X = 1
ok
8> try (X=4) of Val ->{normal,Val}  catch error:Error -> {error,Error}  end.
{error,{badmatch,4}}
9>

Bingo成功.
结论: 要非常小心Erlang语法的变量绑定,在不同的路线会有不同的绑定,容易出问题.

Post Footer automatically generated by wp-posturl plugin for wordpress.

  1. litaocheng
    April 6th, 2010 at 10:39 | #1

    恩,执行完语句哦,f()一下,最有效 🙂

  2. 黑野兽
    April 6th, 2010 at 12:58 | #2

    学习了.

  3. ejon
    April 7th, 2010 at 18:01 | #3

    呵呵,原来是Error已经匹配过了,用f()释放一下就可以解决。
    如果不分析一下,还真不知道怎么回事。

Comments are closed.