热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

ErlangUbuntuCC++C#.郎咸武<langxianzhe@163.com>同学在erlang-china上p

ErlangUbuntuCC++C#.

郎咸武  同学在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语法的变量绑定,在不同的路线会有不同的绑定,容易出问题.
推荐阅读
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 本文介绍了Oracle存储过程的基本语法和写法示例,同时还介绍了已命名的系统异常的产生原因。 ... [详细]
  • 使用圣杯布局模式实现网站首页的内容布局
    本文介绍了使用圣杯布局模式实现网站首页的内容布局的方法,包括HTML部分代码和实例。同时还提供了公司新闻、最新产品、关于我们、联系我们等页面的布局示例。商品展示区包括了车里子和农家生态土鸡蛋等产品的价格信息。 ... [详细]
  • 十大经典排序算法动图演示+Python实现
    本文介绍了十大经典排序算法的原理、演示和Python实现。排序算法分为内部排序和外部排序,常见的内部排序算法有插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等。文章还解释了时间复杂度和稳定性的概念,并提供了相关的名词解释。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • 本文探讨了C语言中指针的应用与价值,指针在C语言中具有灵活性和可变性,通过指针可以操作系统内存和控制外部I/O端口。文章介绍了指针变量和指针的指向变量的含义和用法,以及判断变量数据类型和指向变量或成员变量的类型的方法。还讨论了指针访问数组元素和下标法数组元素的等价关系,以及指针作为函数参数可以改变主调函数变量的值的特点。此外,文章还提到了指针在动态存储分配、链表创建和相关操作中的应用,以及类成员指针与外部变量的区分方法。通过本文的阐述,读者可以更好地理解和应用C语言中的指针。 ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • 本文讨论了如何在codeigniter中识别来自angularjs的请求,并提供了两种方法的代码示例。作者尝试了$this->input->is_ajax_request()和自定义函数is_ajax(),但都没有成功。最后,作者展示了一个ajax请求的示例代码。 ... [详细]
  • Python爬虫中使用正则表达式的方法和注意事项
    本文介绍了在Python爬虫中使用正则表达式的方法和注意事项。首先解释了爬虫的四个主要步骤,并强调了正则表达式在数据处理中的重要性。然后详细介绍了正则表达式的概念和用法,包括检索、替换和过滤文本的功能。同时提到了re模块是Python内置的用于处理正则表达式的模块,并给出了使用正则表达式时需要注意的特殊字符转义和原始字符串的用法。通过本文的学习,读者可以掌握在Python爬虫中使用正则表达式的技巧和方法。 ... [详细]
  • STM32与FPGA的对比及学习建议
    本文对比了野火STM32F103指南针板和Xilinx的PYNQ-Z2板(ZYNQ-7020),介绍了野火STM32F103指南针板的学习资料和讲解视频的详细程度,建议初学者学习野火的资料。同时,介绍了STM32开发所用的Keil程序和C指针的重要性。对于ZYNQ-7020的开发,提到了其自带的Linux、Ubuntu18.4系统以及使用SD卡烧入镜像的方法。 ... [详细]
  • 本文整理了315道Python基础题目及答案,帮助读者检验学习成果。文章介绍了学习Python的途径、Python与其他编程语言的对比、解释型和编译型编程语言的简述、Python解释器的种类和特点、位和字节的关系、以及至少5个PEP8规范。对于想要检验自己学习成果的读者,这些题目将是一个不错的选择。请注意,答案在视频中,本文不提供答案。 ... [详细]
  • 本文详细介绍了使用C#实现Word模版打印的方案。包括添加COM引用、新建Word操作类、开启Word进程、加载模版文件等步骤。通过该方案可以实现C#对Word文档的打印功能。 ... [详细]
  • 在C#中,使用关键字abstract来定义抽象类和抽象方法。抽象类是一种不能被实例化的类,它只提供部分实现,但可以被其他类继承并创建实例。抽象类可以用于类、方法、属性、索引器和事件。在一个类声明中使用abstract表示该类倾向于作为其他类的基类成员被标识为抽象,或者被包含在一个抽象类中,必须由其派生类实现。本文介绍了C#中抽象类和抽象方法的基础知识,并提供了一个示例代码。 ... [详细]
  • 本文介绍了在Web应用系统中,数据库性能是导致系统性能瓶颈最主要的原因之一,尤其是在大规模系统中,数据库集群已经成为必备的配置之一。文章详细介绍了主从数据库架构的好处和实验环境的搭建方法,包括主数据库的配置文件修改和设置需要同步的数据库等内容。MySQL的主从复制功能在国内外大型网站架构体系中被广泛采用,本文总结了作者在实际的Web项目中的实践经验。 ... [详细]
author-avatar
那时候的我和你_173
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有