我知道这$@
是一个全局变量,但我仍然无法弄清楚为什么我需要在使用eval之前对其进行本地化:
例如:
eval { SOME_FUNC_THAT_MAY_DIE(); };
if ($@) {
print "An error occured!\n";
}
我能想到的唯一可能的事情是,如果某个信号处理程序会die
在我尝试读取的同时调用,$@
我在这里错过了什么?
local $@
打电话前说的原因eval
是为了避免踩到你的来电者的$@
。子程序更改任何全局变量是不礼貌的(除非这是子程序的既定目的之一)。对于顶级代码(不在任何子例程中),这并不是真正的问题。
此外,在较旧的 Perl 上,除非首先本地化,否则eval
在对象销毁期间调用的任何调用都会破坏全局(如果由于从块$@
中抛出异常而导致对象被销毁)。这已在 5.14.0 中修复,但许多人仍在运行旧版 Perls。eval
$@
Try::Tiny模块文档给出了基本原理(并提供了替代方案):
当您运行 eval 块并且它成功时,$@ 将被清除,可能会破坏当前正在捕获的错误。这会导致远处的动作,清除调用者可能尚未处理的先前错误。$@ 必须在调用 eval 之前正确本地化以避免此问题。更具体地说,$@ 在 eval 开始时被破坏,这也使得在你死之前无法捕获先前的错误(例如,当使用错误堆栈创建异常对象时)。
您不需要,但如果您编写这样的代码,本地化 $@ 将使第一个错误保持原样。如果您没有编写这样的代码,则本地 $@ 将无效。更好的是在运行任何额外代码之前处理错误。
eval {
die "error 1\n";
};
foo();
print "processing $@\n";
sub foo {
#local $@;
eval {
die "error 2\n";
};
}