为什么我需要在使用eval之前对$ @进行本地化?

问题描述 投票:6回答:3

[我知道$@是全局变量的事实,但我仍然不知道为什么在使用eval之前需要对其进行本地化:

例如:

eval { SOME_FUNC_THAT_MAY_DIE(); };
if ($@) {
  print "An error occured!\n";
}

我唯一想到的是,如果某些信号处理程序在尝试读取die的同时会调用$@,那么我在这里缺少什么?

perl exception eval die
3个回答
12
投票

呼叫local $@之前说eval的原因是避免踩到呼叫者的$@。子例程更改任何全局变量是不礼貌的(除非这是该子例程的既定目的之一)。顶层代码(不是在任何子例程中)并不是真正的问题。

[此外,在较旧的Perl上,在对象破坏期间调用的任何eval都会破坏全局$@(如果由于从eval块引发异常而破坏了对象),除非首先对$@进行了本地化。这是fixed in 5.14.0,但许多人仍在运行旧的Perls。


9
投票

Try::Tiny模块文档提供了基本原理(并提供了替代方法:

当您运行一个eval块并成功执行时,$ @将被清除,可能破坏当前捕获的错误。这会导致一定距离的操作,清除呼叫者可能尚未处理的先前错误。为了避免此问题,在调用eval之前,必须正确定位$ @。更具体地说,$ @在评估的开始就被破坏了,这也使得在死之前无法捕获先前的错误(例如,在使带有错误堆栈的异常对象时)。

0
投票

您不需要,但是如果您编写这样的代码,则对$ @进行本地化将使第一个错误保持原样。如果您未编写此类代码,则本地$ @将无效。最好是在运行任何其他代码之前先处理错误。

eval {
    die "error 1\n";
};
foo();
print "processing $@\n";

sub foo {
    #local $@;
    eval {
        die "error 2\n";
    };
}
© www.soinside.com 2019 - 2024. All rights reserved.