Eri*_*rom 25
Perl eval有两种版本,字符串eval和block eval.String eval调用编译器来执行源代码.块eval将已编译的代码包含在将捕获die异常的包装器中.(字符串eval也捕获die异常,以及任何编译错误).
Try :: Tiny仅适用于eval的块形式,但以下内容适用于两种形式.
每次调用eval它都会改变它的值$@.它将是''eval成功或者eval捕获的错误.
这意味着只要您调用eval,就会清除以前的任何错误消息. 为您Try::Tiny本地化$@变量,以便成功的eval不会清除先前失败的eval的消息.
另一个陷阱来自于使用$@检查来确定eval是否成功.一种常见的模式是:
eval {...};
if ($@) {
# deal with error here
}
Run Code Online (Sandbox Code Playgroud)
这依赖于两个假设,首先,任何错误消息$@都可以包含一个真值(通常为真),并且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
};
Run Code Online (Sandbox Code Playgroud)
逐行拆分,为块local $@创建一个新的$@,以do防止破坏以前的值. my $ret将是评估代码的返回值.在eval块中,$ret分配给,然后块返回1.这样,无论如何,如果eval成功,它将返回true,如果失败则返回false.在失败的情况下,由您决定该怎么做.上面的代码就死了,但您可以轻松地使用eval块的返回值来决定运行其他代码.
由于上述咒语有点单调乏味,因此容易出错.使用类似的模块Try::Tiny将您与这些潜在的错误隔离开来,代价是每个eval会有更多的函数调用.了解如何正确使用eval非常重要,因为Try::Tiny如果必须使用字符串eval ,则不会对您有所帮助.
除了上面的答案,我还会补充......
$SIG{__DIE__}处理程序影响,导致远程操作.eval BLOCK和eval STRING,因为他们似乎做同样的事情,但一个是一个安全漏洞.Try :: Tiny有自己的陷阱,最大的问题是虽然它看起来像一个块,但它实际上是一个子程序调用.这意味着:
eval {
...blah blah...
return $foo;
};
Run Code Online (Sandbox Code Playgroud)
还有这个:
try {
...blah blah...
return $foo;
};
Run Code Online (Sandbox Code Playgroud)
不要做同样的事情.这些是在Try :: Tiny文档的CAVEATS部分中列出的.那就是说,我推荐它eval.
| 归档时间: |
|
| 查看次数: |
11567 次 |
| 最近记录: |