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