[我知道$@
是全局变量的事实,但我仍然不知道为什么在使用eval之前需要对其进行本地化:
例如:
eval { SOME_FUNC_THAT_MAY_DIE(); };
if ($@) {
print "An error occured!\n";
}
我唯一想到的是,如果某些信号处理程序在尝试读取die
的同时会调用$@
,那么我在这里缺少什么?
呼叫local $@
之前说eval
的原因是避免踩到呼叫者的$@
。子例程更改任何全局变量是不礼貌的(除非这是该子例程的既定目的之一)。顶层代码(不是在任何子例程中)并不是真正的问题。
[此外,在较旧的Perl上,在对象破坏期间调用的任何eval
都会破坏全局$@
(如果由于从eval
块引发异常而破坏了对象),除非首先对$@
进行了本地化。这是fixed in 5.14.0,但许多人仍在运行旧的Perls。
Try::Tiny模块文档提供了基本原理(并提供了替代方法:
当您运行一个eval块并成功执行时,$ @将被清除,可能破坏当前捕获的错误。这会导致一定距离的操作,清除呼叫者可能尚未处理的先前错误。为了避免此问题,在调用eval之前,必须正确定位$ @。更具体地说,$ @在评估的开始就被破坏了,这也使得在死之前无法捕获先前的错误(例如,在使带有错误堆栈的异常对象时)。
您不需要,但是如果您编写这样的代码,则对$ @进行本地化将使第一个错误保持原样。如果您未编写此类代码,则本地$ @将无效。最好是在运行任何其他代码之前先处理错误。
eval {
die "error 1\n";
};
foo();
print "processing $@\n";
sub foo {
#local $@;
eval {
die "error 2\n";
};
}