对try 异常 运行的疑问,为什么出现两种结果
April 5th, 2010
3 comments
原创文章,转载请注明: 转载自系统技术非业余研究
本文链接地址: 对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.
Recent Comments