我正在研究掌握 Perl 的“错误处理和报告”章节。在 perlvar 的
$@
条目中,它说:
来自最后一个 eval() 运算符的 Perl 语法错误消息。如果 $@ 是空字符串,则最后一个 eval() 会正确解析并执行(尽管您调用的操作可能以正常方式失败)。
现在我想知道 eval 何时可能无法正确执行,从而使
$@
具有未定义的值。有这样的案例吗?
这是一种方法(但在阅读之前请坐下。;))
$@ = 123;
eval q{
$@ = 456;
print ">>>$@<<<\n";
goto SKIP;
};
SKIP:
print ">>>$@<<<\n";
Try::Tiny 文档的 BACKGROUND 部分包含一些有关如何破坏
$@
以及为什么 Try::Tiny 特别注意避免破坏的信息,并且始终测试 eval
的返回值而不是测试$@
为了真理。他们所有人都在那里,因为某人在某个时候遇到了他们,但我认为eval
-in-DESTROY
的场景是最有可能绊倒某人的。基本上,如果 die
导致某个对象超出范围,并且该对象有一个 DESTROY
调用 eval
,那么您最初使用 die
的值将无法挽回地丢失。假设 eval
中的 DESTROY
不抛出错误,$@
将是
""
跟随外部
eval
。
$@
设置为 undef 的事?“最后一个 eval() 正确解析并执行”没有任何意义:
eval
在运行时不被解析。当然,它的意思是“最后一个表达式被正确解析和执行的 eval()”。换句话说,“最后一个 eval() 的表达式已编译并且在执行时没有抛出任何异常”。
>perl -MData::Dumper -e"$@=123; eval ''; print(Dumper($@));"
$VAR1 = '';
>perl -MData::Dumper -e"$@=123; eval '~~~'; print(Dumper($@));"
$VAR1 = 'syntax error at (eval 1) line 2, at EOF
';
>perl -MData::Dumper -e"$@=123; eval 'die q{x}'; print(Dumper($@));"
$VAR1 = 'x at (eval 1) line 1.
';
$@
在
eval
之后是否可以未定义,我相信答案是否定的。 (我还在 $@的旧 5.8.3 文档中读到它是“null”,我很困惑,因为“null”不是 Perl 中经常使用的术语。) 我不了解 Perl 内部知识来确认这一点,但看起来文档最终在 2015 年通过 this commit
修复,这是由于 this 问题 产生的。 perlvar 的条目 现在显示“空字符串”而不是“null”:
来自最后一个“eval”运算符的 Perl 错误,即捕获的最后一个异常。对于“eval BLOCK”,这要么是运行时错误消息,要么是调用“die”时使用的字符串或引用。 “eval STRING”形式还可以捕获语法错误和其他编译时异常。此外,鉴于 $@ 可以设置为“调用模具的字符串或引用模具”,我想我会确保如果没有错误发生,“eval”将 $@ 设置为空字符串。
die undef
没有这样做。事实上,这样做是由 Perl 捕获和处理的:
% perl -we 'eval { die undef }; print "EVAL_ERROR: $@"'
Use of uninitialized value in die at -e line 1.
EVAL_ERROR: Died at -e line 1.