使用Perl';什么是评估?

使用Perl';什么是评估?,perl,exception,eval,Perl,Exception,Eval,与Perl相关联的常见陷阱有哪些,这些陷阱可能会让您选择使用模块,例如?这些问题将在中解释。简而言之,它们是: Perl的eval有两种风格,字符串eval和块eval。String eval调用编译器来执行源代码。Block eval将已编译的代码包围在一个包装器中,该包装器将捕获die异常。(字符串eval还捕获die异常以及任何编译错误) Try::Tiny仅适用于eval的块形式,但以下两种形式都适用 每次调用eval时,它都会更改$@的值。如果评估成功或被评估捕获到错误,则它将

与Perl相关联的常见陷阱有哪些,这些陷阱可能会让您选择使用模块,例如?

这些问题将在中解释。简而言之,它们是:


    • Perl的
      eval
      有两种风格,字符串eval和块eval。String eval调用编译器来执行源代码。Block eval将已编译的代码包围在一个包装器中,该包装器将捕获
      die
      异常。(字符串eval还捕获
      die
      异常以及任何编译错误)

      Try::Tiny仅适用于eval的块形式,但以下两种形式都适用

      每次调用
      eval
      时,它都会更改
      $@
      的值。如果评估成功或被评估捕获到错误,则它将是
      '

      这意味着,无论何时调用eval,都将清除以前的所有错误消息
      Try::Tiny
      为您本地化
      $@
      变量,以便成功的评估不会清除先前失败评估的消息

      另一个陷阱是使用
      $@
      作为检查来确定评估是否成功。一种常见的模式是:

      eval {...};
      if ($@) {
         # deal with error here
      }
      
      这取决于两个假设,首先,任何错误消息
      $@
      可能包含的值都是真值(通常为真),并且eval块和if语句之间没有代码

      从视觉上看,后者当然是正确的,但是如果eval块创建了一个对象,并且该对象在eval失败后超出了范围,那么该对象的
      DESTROY
      方法将在
      if
      语句之前被调用。如果
      DESTROY
      碰巧调用eval而没有本地化
      $@
      ,并且调用成功,那么在运行
      If
      语句时,
      $@
      变量将被清除

      解决这些问题的办法是:

      my $return = do {
          local $@;
          my $ret;
          eval {$ret = this_could_fail(); 1} or die "eval failed: $@";
          $ret
      };
      
      将该行逐行分解,本地$@会为
      do
      块创建一个新的
      $@
      ,以防止对以前的值进行碰撞
      my$ret
      将是计算代码的返回值。在eval块中,
      $ret
      被分配给,然后块返回
      1
      。这样,不管怎样,如果eval成功,它将返回true,如果失败,它将返回false。万一失败,该怎么办由你决定。上面的代码刚刚结束,但是您可以很容易地使用eval块的返回值来决定运行其他代码


      因为上面的咒语有点乏味,所以很容易出错。使用像
      Try::Tiny
      这样的模块可以将您从这些潜在错误中隔离出来,而每次评估的代价是多调用几个函数。知道如何正确使用eval是很重要的,因为如果必须使用字符串eval,
      Try::Tiny
      对您没有帮助。

      除了上面的答案,我还要补充

      • eval受全局
        $SIG{{uuuuu DIE}
        处理程序的影响,该处理程序在一定距离内导致操作
      • 新手很容易混淆
        eval BLOCK
        eval STRING
        ,因为它们似乎做了相同的事情,但其中一个是安全漏洞
      Try::Tiny有它自己的缺点,最大的缺点是它看起来像块,但实际上是一个子程序调用。这意味着:

      eval {
          ...blah blah...
          return $foo;
      };
      
      这是:

      try {
          ...blah blah...
          return $foo;
      };
      

      不要做同样的事情。这些都在地图上标出了。也就是说,我建议使用eval-on-X11函数,而不要使用eval-on-X11函数

      代码如下

      eval {    
          @win_arrays = GetWindowsFromPid($pid);
      };
      
      脚本将从中退出

      失败请求的X错误:


      可能重复,您不使用内置的唯一原因是您没有运行当前版本的Perl。@mob-是的,这似乎是同一个问题。运行5.14或更高版本,告诉我这是否适用于您。@tchrist确实适用。谢谢你指出这一点。我真不敢相信我错过了。这里是供参考的链接:谢谢。虽然我在Try:Tiny上阅读了介绍,但我未能阅读背景部分。在当前版本中已修复。在当前版本中已修复。如果没有引发异常,则Tiny correction-
      $@
      实际上将是一个空字符串,而不是未定义。@Grant McLean=>谢谢,我应该记得,因为这就是我通常的repl处理错误的方式:
      perl-我们说eval,$@而“
      你是说
      eval
      在5.14中仍然无法使用吗?真正地这将是非常令人失望的,因为我知道它做了很多工作,试图通过修复任何困扰
      eval
      的底层bug,使
      try::Tiny
      过时。如果这一努力失败了,那么就会出现一个可怕的问题,因为
      Try::Tiny
      仍然只是一个CPAN模块,而不是核心。如果你不能用核心做真正的、可靠的工作,那么这是一个不可接受的情况。@tchrist忘记了这一点。据我所知,5.14.0修复了一类与$@和对象销毁之间的交互有关的bug,通常使
      eval{…};如果($@){…}
      更可靠。我相信这可以解决三件事情中的两件:微小的修复。。。第三个(错误的$@)是不太可能的。它仍然保留了我提到的要点。这将是一个很好的5.16特性,可以阻止$SIG{{{uuuuu DIE}在一个eval内开火。然后把话剧往下拨,伙计。把
      eval STRING
      称为“安全问题”不仅仅是太戏剧化了;这甚至不是真的。我使用了
      eval STRING
      ,因为它在23年前首次出现在perl2中,我可以向您保证,我从未遇到过任何所谓的“安全问题”。当然,愚蠢的程序员可以用它做愚蠢的事情,但这几乎适用于任何事情。如果你生活在一个病态偏执的世界,你应该使用污染模式和/或安全隔间。在正常情况下,
      eval STRING
      会得到很多u