`
mryufeng
  • 浏览: 968462 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

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

阅读更多
郎咸武<langxianzhe@163.com>  同学在erlang-china上post了一个问题:
请注意编号为91和92两行运行结果,请问为什么会出现两种结果。
一个抛出 {error,{badmatch,5}}
另一个抛出** exception error: no match of right hand side value 4
view source
print?
01 root@ubuntu:/usr/src/otp# erl
02 Erlang R13B04 (erts-5.7.5) [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false
03 88> X=1.
04 1
05 89> try (X=5) of Val ->{normal,Val} catch error:Error -> {error,Error}  end.
06 {error,{badmatch,5}}
07 90> try (X=1) of Val ->{normal,Val} catch error:Error -> {error,Error}  end.
08 {normal,1}
09 91> try (X=5) of Val ->{normal,Val} catch error:Error -> {error,Error}  end.
10 {error,{badmatch,5}}
11 92> try (X=4) of Val ->{normal,Val} catch error:Error -> {error,Error}  end.
12 ** exception error: no match of right hand side value 4
13 93> self().
14 <0.36.0>
15 94> catch try (X=4) of Val  ->{normal,Val} catch error:Error -> {error,Error}  end. %%这个异常是 shell捕获到了 进一步处理后的结果
16 {'EXIT',{{badmatch,4},[{erl_eval,expr,3}]}}
17 95> try (X=4) of Val ->{normal,Val} catch error:Error ->  {error,Error}  end.
18 ** exception error: no match of right hand  side value 4
19 96> self().
20 <0.36.0>

竟然是EXIT, 这时候shell也换了pid了, 这是怎么回事呢?
由于在shell输入的程序是公司允许的, 我们也可以从出错的stack里面看到是 erl_eval:expr函数异常了.
现在让我们对系统打patch如下:
lib/stdlib/src/erl_eval.erl
view source
print?
1 282expr({match,_,Lhs,Rhs0},  Bs0, Lf, Ef, RBs) ->
2 283    {value,Rhs,Bs1} = expr(Rhs0, Bs0,  Lf, Ef, none),
3 284    case match(Lhs, Rhs, Bs1) of
4 285         {match,Bs} ->
5 286            ret_expr(Rhs, Bs, RBs);
6 287        nomatch ->
7 288            io:format("expr nomatch->pid:~p~n~p~n",[self(), Rhs]),   %%添加诊断
8 289             erlang:raise(error, {badmatch,Rhs}, stacktrace())
9 290    end;

erts/emulator/beam/bif.c
view source
print?
01 1142/**********************************************************************/
02 1143/*  raise an exception of given class, value and  stacktrace.
03 1144  *
04 1145 * If there is an error in the argument  format,
05 1146 * return the atom 'badarg'  instead.
06 1147 */
07 1148Eterm
08 1149raise_3(Process *c_p, Eterm class,  Eterm value, Eterm stacktrace) {
09 ...
10 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); /*添加诊断*/
11 1223    BIF_ERROR(c_p, reason);
12 ...
13 }

然 后我们在运行上面的语句:
view source
print?
01 root@ubuntu:~/otp#  bin/erl
02 Erlang R13B04 (erts-5.7.5) [source]  [smp:2:2] [rq:2]  [async-threads:0] [kernel-poll:false]
03
04 Eshell  V5.7.5  (abort with  ^G)
05 1> X=1.
06 1
07 2>  try (X=5) of Val ->{normal,Val}  catch error:Error ->  {error,Error}  end.
08 expr nomatch->pid:<0.32.0>
09 5
10 raise->proc:<0.32.0>
11 class=error
12 value={badmatch,5}
13 stacktrace=[[{erl_eval,expr,3}
14 {error,{badmatch,5}}
15 3>  try  (X=4) of Val ->{normal,Val} catch  error:Error -> {error,Error}   end.
16 expr nomatch->pid:<0.32.0>
17 4
18 raise->proc:<0.32.0>
19 class=error
20 value={badmatch,4}
21 stacktrace=[[{erl_eval,expr,3}]|-000000000000000016]
22 raise->proc:<0.32.0>
23 class=error
24 value={badmatch,4}
25 stacktrace=[[{erl_eval,expr,3}]|-000000000000000016]

很奇怪的是第3句raise了2次. 让我们回到程序好好看下:
view source
print?
1 X=1.   %%这行绑定了一个变量X=1
2 try (X=5) of Val ->{normal,Val} catch  error:Error -> {error,Error}  end.   %%这行由于异常会试图绑定变量Error={badmatch,5}, 由于之前Error不存在, 绑定成功.
3 try  (X=4) of Val ->{normal,Val} catch error:Error -> {error,Error}   end.   %%这行由于异常会绑定了变量Error={badmatch,4}, 由于Error存在,  而且值是{badmatch,5},所以这时候catch就出
4 现异常了,  往外抛出{'EXIT',{{badmatch,4},[{erl_eval,expr,3}]}}.

这 下我们明白了, 是这个catch惹的祸了.
我们再实验下我们的分析:
view source
print?
01 root@ubuntu:~#  erl
02 Erlang R13B04 (erts-5.7.5) [source] [smp:2:2] [rq:2]  [async-threads:0] [hipe] [kernel-poll:false]
03
04 Eshell V5.7.5   (abort with ^G)
05 1> X=1.
06 1
07 2> b().
08 X = 1
09 ok
10 3>  try (X=5) of Val ->{normal,Val} catch error:Error ->  {error,Error}  end.
11 {error,{badmatch,5}}
12 4> b().
13 Error =  {badmatch,5}
14 X = 1
15 ok
16 5> try (X=4) of Val ->{normal,Val}  catch error:Error -> {error,Error}  end.
17 ** exception error: no  match of right hand side value 4
18 6> f(Error).
19 ok
20 7>  b().
21 X = 1
22 ok
23 8> try (X=4) of Val ->{normal,Val}  catch error:Error -> {error,Error}  end.
24 {error,{badmatch,4}}
25 9>

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

相关推荐

Global site tag (gtag.js) - Google Analytics