可能重复:
How can I cleanly handle error checking in Perl?
What’s broken about exceptions in Perl?
我看到代码的效果如下:
do_something($param) || warn "something went wrong\n";
我也看到了这样的代码:
eval {
do_something_else($param);
};
if($@) {
warn "something went wrong\n";
}
我应该在所有子程序中使用eval / die吗?我应该根据子程序返回的内容编写所有代码吗?不是eval
代码(一遍又一遍)会让我慢下来吗?
答案 0 :(得分:13)
阻止eval
不是字符串eval
,所以不,它不慢。绝对推荐使用它。
它的工作方式有一些令人烦恼的微妙之处(大多数令人讨厌的$@
是一个全局变量的副作用),所以考虑使用Try::Tiny而不是记住所有的你需要在防御性地使用eval
的小技巧。
答案 1 :(得分:6)
do_something($param) || warn "something went wrong\n";
在这种情况下,如果出现问题,do_something
应返回错误代码。要么它不能死,要么它死了,这是一个非常不寻常的情况。
eval { do_something_else($param); }; if($@) { warn "something went wrong\n"; }
这里假设do_something_else
通过抛出异常来解决出错的唯一机制。
如果do_something_else
在真正异常情况下抛出异常并在其他情况下返回错误值,则还应检查其返回值。
使用eval的块形式不会在运行时导致额外的编译,因此没有严重的性能缺陷:
在第二种形式中,BLOCK中的代码只被解析一次 - 同时解析
eval
本身周围的代码 - 并在当前Perl程序的上下文中执行。此表单通常用于比第一个表单更有效地捕获异常(见下文),同时还提供了在编译时检查BLOCK
内的代码的好处。
答案 2 :(得分:6)
warn
非常讨厌的模块。成功或失败。不要在终端上打印东西然后继续运行;我的程序无法根据您打印的某些消息采取措施。如果程序可以继续运行,只有在明确告知它没有问题时才打印一条消息。如果程序无法继续运行,die
。这就是它的用途。
当出现问题时,始终抛出异常。如果您可以解决问题,请修复它。如果你无法解决问题,请不要尝试;抛出异常并让调用者处理它。 (如果你不能处理你呼叫的异常,请不要。)
基本上,许多程序出错的原因是因为他们试图修复他们无法解决的错误。在问题的第一个迹象下干净地死亡的程序易于调试和修复。一个在困惑时继续运行的程序只会破坏数据并使每个人烦恼。所以不要这样做。尽快死去。
答案 3 :(得分:5)
你的两个例子完全不同。第一个检查错误的返回值,并采取一些响应操作。第二个检查被叫代码的实际死亡。
您必须自己决定哪种行为适合每种情况。我建议在大多数情况下简单地返回false。如果您遇到严重到无法继续的错误(或者没有任何意义继续下去,那么您应该只明确die
。但即便如此,您仍然可以返回错误。
在eval {}
中包含块与在eval ""
中包装任意代码不同。在前一种情况下,代码仍然在编译时解析,并且您不会产生任何额外的开销。您将简单地捕获该代码的任何死亡(但除了在$@
中留给您的值之外,您不会有任何关于出现问题或代码有多远的迹象)。在后一种情况下,Perl解释器将代码视为一个简单的字符串,直到它被实际评估为止,因此在调用解释器时会有一定的成本(并且您将失去对代码的所有编译时检查)。 / p>
顺便提一下,您调用eval
并检查$@
值的方式不是推荐形式;有关Perl中异常陷阱和技术的广泛讨论,请参阅this discussion。
答案 4 :(得分:2)
第一个版本非常“perlish”,非常简单易懂。这个成语的唯一缺点是它只对短的情况可读。如果错误处理需要更多逻辑,请使用第二个版本。
答案 5 :(得分:2)
没有人真正解决过这个问题的“最佳实践”部分,所以我会跳进去。
是的,你应该肯定在出现问题时在你的代码中抛出一个异常,你应该尽早这样做(所以你要限制需要调试的代码来解决什么是导致它。)
执行返回undef
以表示失败的代码并不是特别可靠,因为人们倾向于使用它而不检查undef returnvalue - 这意味着他们假设的变量实际上有一些有意义的东西不得。这导致了复杂,难以调试的问题,甚至在以前工作的代码中出现意外问题。
更加可靠的方法是编写代码,以便在出现问题时将其终止,然后只有在需要从该故障中恢复时,才能在{{1>中包含对它的任何调用(或者,更好,来自Try::Tiny的eval{ .. }
,如上所述)。在大多数情况下,调用代码无法进行任何有意义的恢复,因此在常见情况下调用代码仍然很简单,您可以假设您将获得有用的值。如果出现问题,那么您将从失败的代码的实际部分收到错误消息,而不是默默地获取undef。如果您的调用代码可以做一些事情来恢复失败,那么它可以安排捕获异常并做任何需要的事情。
值得一读的东西是Exception classes,它是一种将额外信息发送到调用代码的结构化方法,并允许它选择要捕获的异常以及无法处理的异常。您可能不希望在代码中的任何地方使用它们,但是如果您有一些复杂的东西可能会以同样复杂的方式失败,并且您希望安排失败可以恢复,那么它们是一种有用的技术。