解决方法
Perl的eval有两种口味,即字符串eval和block eval. String eval调用编译器来执行源代码.块eval包围已经编译的代码,可以捕获模块异常. (string eval也捕获模块异常以及任何编译错误).
Try :: Tiny仅适用于eval的块形式,但以下内容适用于这两种形式.
每次调用eval它都会改变$@的值.如果eval成功或者eval所捕获的错误,它将是“’”
这意味着您随时调用eval,您将清除以前的任何错误消息. Try :: Tiny为您定制$@变量,以便成功的eval不会清除以前失败的eval的消息.
另一个陷阱来自使用$@作为检查来确定eval是否成功.一个常见的模式是:
eval {...}; if ($@) { # deal with error here }
这依赖于两个假设,首先,任何错误消息$@可以包含是一个真实值(通常为true),并且eval块和if语句之间没有代码.
当然,后者是真实的,但是如果eval块创建了一个对象,并且该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块创建一个新的$@,这阻止了以前的值的颠覆.我的$ret将是评估代码的返回值.在eval块中,$ret被分配给,然后块返回1.这样,无论什么,如果eval成功,它将返回true,如果失败,它将返回false.在失败的情况下,由你自己决定.上面的代码只是死了,但你可以很容易地使用eval块的返回值来决定运行其他代码.
由于上述咒语有点乏味,容易出错.使用像Try :: Tiny这样的模块可以使您免受这些潜在的错误,每个eval都需要多一些函数调用.知道如何正确地使用eval是很重要的,因为如果你必须使用字符串eval,Try :: Tiny不会帮助你.