6

我知道这$@是一个全局变量,但我仍然无法弄清楚为什么我需要在使用eval之前对其进行本地化:

例如:

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

我能想到的唯一可能的事情是,如果某个信号处理程序会die在我尝试读取的同时调用,$@我在这里错过了什么?

4

3 回答 3

12

local $@打电话前说的原因eval是为了避免踩到你的来电者的$@。子程序更改任何全局变量是不礼貌的(除非这是子程序的既定目的之一)。对于顶级代码(不在任何子例程中),这并不是真正的问题。

此外,在较旧的 Perl 上,除非首先本地化,否则eval在对象销毁期间调用的任何调用都会破坏全局(如果由于从块$@中抛出异常而导致对象被销毁)。这已在 5.14.0 中修复,但许多人仍在运行旧版 Perls。eval$@

于 2012-07-04T19:50:04.757 回答
9

Try::Tiny模块文档给出了基本原理(并提供了替代方案):

当您运行 eval 块并且它成功时,$@ 将被清除,可能会破坏当前正在捕获的错误。这会导致远处的动作,清除调用者可能尚未处理的先前错误。$@ 必须在调用 eval 之前正确本地化以避免此问题。更具体地说,$@ 在 eval 开始时被破坏,这也使得在你死之前无法捕获先前的错误(例如,当使用错误堆栈创建异常对象时)。
于 2012-07-04T19:47:04.073 回答
0

您不需要,但如果您编写这样的代码,本地化 $@ 将使第一个错误保持原样。如果您没有编写这样的代码,则本地 $@ 将无效。更好的是在运行任何额外代码之前处理错误。

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

sub foo {
    #local $@;
    eval {
        die "error 2\n";
    };
}
于 2020-01-28T21:57:44.543 回答