Perl中eval捕获异常后调用die出现...propagated提示的文档在哪里?
Perl无参数die重复输出eval历史异常问题
问题描述
如下代码中,eval用于校验正则表达式是否合法,捕获到异常后代码自行打印了异常内容,程序不会在此处终止,运行符合预期。
但后续执行die;语句时,之前的异常文本会在未主动调用的情况下再次被打印,还会追加...propagated消息和die;语句对应的行号。此时该异常文本与当前场景不匹配,极易造成混淆。看起来Perl会一直保留eval的错误消息或异常消息,直到遇到die;为止。
下文附的复现代码下方提供了两种规避方案,任意一种都可以消除该行为。请问该特殊行为在何处有官方文档说明?其设计思路是什么?
复现代码
#!/usr/bin/perl use strict; use warnings; my $str=q/(d/; my $rgx; eval{$rgx=qr/$str/}; if(length $@) { print join('', 'qr/', $str, '/ does not compile: ',"\n", $@, ); } print "Got past eval. But next, at 'die;', it will print an error message that no longer pertains.\n"; die;
规避方案1:给die;传入非空字符串
#!/usr/bin/perl use strict; use warnings; my $str=q/(d/; my $rgx; eval{$rgx=qr/$str/}; if(length $@) { print join('', 'qr/', $str, '/ does not compile: ',"\n", $@, ); } print "Got past eval. Next, the nonempty string in die ' '; flushes out the inappropriate exception message.\n"; die ' ';
规避方案2:执行另一个没有语法错误的eval
#!/usr/bin/perl use strict; use warnings; my $str=q/(d/; my $rgx; eval{$rgx=qr/$str/}; if(length $@) { print join('', 'qr/', $str, '/ does not compile: ',"\n", $@, ); } print "got past eval\n"; $str=0; eval{$rgx=qr/$str/}; die;
官方解答
文档出处
该行为是Perl的预设正常逻辑,在Perl核心内置函数die的官方文档中有明确说明,执行perldoc -f die即可查看完整内容,相关规则翻译如下:
当
die调用时未传入任何参数:
- 如果特殊变量
$@(存储最近一次eval捕获的异常内容)非空,会输出$@的内容,末尾追加...propagated和当前die语句的行号- 如果
$@为空,会输出默认提示Died加当前行号
设计思路
该特性是为了简化异常传播场景的开发:当在eval中捕获到异常、完成当前层级的清理、日志等逻辑后,需要将原始异常向上层调用栈抛出时,无需手动编写die $@;,直接调用无参数die即可完成原始异常的透传,既减少了代码冗余,也避免了手动传递异常时可能出现的内容篡改、丢失问题。
规避方案原理
上述两种规避方案都精准匹配了该特性的触发条件,从根源上避免了历史异常被重复输出:
- 方案1给
die传入非空字符串:只要die接收到非空参数,就会直接输出传入的内容,不会再读取$@的历史值 - 方案2执行无异常的
eval:eval块执行未报错时,会自动将$@置为空,后续无参数die就会输出默认的Died提示,不会再带出之前正则编译的异常内容
内容的提问来源于stack exchange,提问作者Jacob Wegelin
相关产品推荐
相关产品推荐

