【问题标题】:Why do I need to localize $@ before using eval?为什么我需要在使用 eval 之前本地化 $@?
【发布时间】:2012-07-05 06:44:14
【问题描述】:

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

例如:

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

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

【问题讨论】:

    标签: perl exception eval die


    【解决方案1】:

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

    此外,在较旧的 Perl 上,在对象销毁期间调用的任何 eval 都会破坏全局 $@(如果对象因为从 eval 块中抛出异常而被销毁),除非 $@ 被本地化第一的。这是fixed in 5.14.0,但许多人仍在运行旧版 Perls。

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

      • 我之所以找到这篇文章,正是因为我没有完全理解 Try::Tiny 文档中的这一段。 potentially clobbering an error that is currently being caught 是什么意思? ;-)
      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-06-15
        • 1970-01-01
        • 2013-08-16
        • 1970-01-01
        • 2015-08-19
        • 1970-01-01
        • 2014-04-10
        • 2016-09-10
        相关资源
        最近更新 更多