郎咸武<langxianzhe@163.com> 同学在erlang-china上post了一个问题:
请注意编号为91和92两行运行结果,请问为什么会出现两种结果。
一个抛出 {error,{badmatch,5}}
另一个抛出** exception error: no match of right hand side value 4
Erlang R13B04 (erts-5.7.5) [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll: false |
89> try (X=5) of Val ->{normal,Val} catch error:Error -> {error,Error} end. |
90> try (X=1) of Val ->{normal,Val} catch error:Error -> {error,Error} end. |
91> try (X=5) of Val ->{normal,Val} catch error:Error -> {error,Error} end. |
92> try (X=4) of Val ->{normal,Val} catch error:Error -> {error,Error} end. |
** exception error: no match of right hand side value 4 |
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 |
竟然是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 |
286 ret_expr( Rhs , Bs , RBs ); |
288 io:format ( "expr nomatch->pid:~p~n~p~n" ,[self(), Rhs ]), |
289 erlang:raise (error, {badmatch, Rhs }, stacktrace()) |
erts/emulator/beam/bif.c
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); |
然 后我们在运行上面的语句:
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) |
2> try (X=5) of Val ->{normal,Val} catch error:Error -> {error,Error} end. |
expr nomatch->pid:<0.32.0> |
stacktrace=[[{erl_eval, expr ,3} |
3> try (X=4) of Val ->{normal,Val} catch error:Error -> {error,Error} end. |
expr nomatch->pid:<0.32.0> |
stacktrace=[[{erl_eval, expr ,3}]|-000000000000000016] |
stacktrace=[[{erl_eval, expr ,3}]|-000000000000000016] |
很奇怪的是第3句raise了2次. 让我们回到程序好好看下:
try (X=5) of Val ->{normal, Val } catch error: Error -> {error, Error } end . |
try (X=4) of Val ->{normal, Val } catch error: Error -> {error, Error } end . |
现异常了, 往外抛出{ 'EXIT' ,{{badmatch,4},[{erl_eval,expr,3}]}}. |
这 下我们明白了, 是这个catch惹的祸了.
我们再实验下我们的分析:
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) |
3> try (X=5) of Val ->{normal,Val} catch error:Error -> {error,Error} end. |
5> try (X=4) of Val ->{normal,Val} catch error:Error -> {error,Error} end. |
** exception error: no match of right hand side value 4 |
8> try (X=4) of Val ->{normal,Val} catch error:Error -> {error,Error} end. |
Bingo成功.
结论: 要非常小心Erlang语法的变量绑定,在不同的路线会有不同的绑定,容易出问题.
Recent Comments