2010-03-07 53 views
4

可能重复:
How can I cleanly handle error checking in Perl?
What’s broken about exceptions in Perl?如果在Perl代码中出现错误,最佳做法是什么?

我看到代码的工作原理是这样的:

do_something($param) || warn "something went wrong\n"; 

,我也看到了这样的代码:

eval { 
    do_something_else($param); 
}; 
if([email protected]) { 
    warn "something went wrong\n"; 
} 

我应该在所有子程序中使用eval/die吗?我应该根据从子例程返回的东西编写我的所有代码吗?是不是eval'代码(一遍又一遍)会减慢我的速度?

+2

假装别人写了吗? ;) – 2010-03-07 11:28:07

+0

是啊:)。有点难以说出作者:Geo。 :) – Geo 2010-03-07 11:29:29

+0

有关Perl中异常的广泛讨论,请参阅http://stackoverflow.com/questions/2165161/whats-broken-about-exceptions-in-perl – Ether 2010-03-07 16:53:27

回答

2

第一个版本非常“完美”,而且非常直观易懂。这个习惯用语的唯一缺点是它只能在短时间内阅读。如果错误处理需要更多逻辑,请使用第二个版本。

13

Block eval不是字符串eval,所以不,它不慢。使用它是绝对推荐的。

有一些恼人的细微之处是它的工作原理虽然这样(的事实[email protected]是一个全局变量大多是讨厌的副作用),所以请考虑使用Try::Tiny,而不是记住所有你需要使用的小动作eval防守。

6
do_something($param) || warn "something went wrong\n"; 

在这种情况下,do_something预计,如果出现错误返回错误代码。要么它不能死亡,要么就是这样,这是一种非常不寻常的情况。

eval { 
    do_something_else($param); 
}; 
if([email protected]) { 
    warn "something went wrong\n"; 
} 

这里,假设是由do_something_else通信出乱子的唯一机制是通过抛出异常。

如果do_something_else在真正例外的情况下抛出异常并在其他情况下返回错误值,您还应该检查其返回值。

使用的eval块形式不会导致在运行时编译外,所以没有严重的性能缺点:

在第二种形式,块内的代码被解析只有一次 - 在同时围绕eval本身的代码被解析 - 并在当前Perl程序的上下文中执行。此表单通常用于比第一个更有效地捕获异常(请参见下文),同时还提供了在编译时检查BLOCK内的代码的好处。

5

你的两个例子完全不同的事情。第一个检查一个错误的返回值,并采取一些行动作为回应。第二个检查被调用代码的实际死亡。

你必须自己决定哪个动作是在每种情况下适当的。我建议在大多数情况下简单地返回false。你只应明确die荷兰国际集团,如果你遇到了错误非常严重,你不能继续(或者没有点在继续,但即使如此,你仍然可以返回false)。

eval {}中包装块与在eval ""中包装任意代码不同。在前一种情况下,代码在编译时仍然被解析,并且不会产生额外的开销。你会简单地赶上代码的任何死亡(但你不会有任何指示,以什么地方出了错或多远,你在你的代码了,但是,被在[email protected]留给你的价值)。在后一种情况下,代码被视为由Perl解释一个简单的字符串,直到它实际上是等价的,所以有一定的成本这里的解释器中调用(和你失去所有的编译时代码的检查)。

顺便说一下,您称为eval并检查值为[email protected]的方式不是推荐形式;有关Perl中异常陷阱和技术的广泛讨论,请参阅this discussion

+0

当我返回false时,我应该怎么去提供错误信息? – Geo 2010-03-07 19:44:01

+0

@Geo:你可以用'warn()'向stderr输出一个字符串,或者使用日志工具(如Log :: Log4perl)记录一条消息。 – Ether 2010-03-07 20:17:35

2

没有人真正解决这个“最佳实践”的一部分,所以我会在跳。

是的,你应该绝对抛出一个异常,在代码中出问题的时候,你应该做的它尽可能早(所以你限制了需要调试的代码来找出造成它的原因)。 ,做这样的东西回报undef来表示失败

代码不是特别可靠,仅仅是因为人们往往会使用它没有检查民主基金返回值 - 这意味着他们假设一个变量一些有意义的,它实际上可能不是。这导致了复杂的,难以调试的问题,甚至在之前的代码中出现意外的问题。

更坚实的方法是编写代码,以便它死,如果出现错误,然后只有当你需要从失败收回,换到它的任何电话中eval{ .. }(或更好,try { .. } catch { .. }如上所述,从Try::Tiny)。在大多数情况下,调用代码可以恢复的内容没有任何意义,所以在常见情况下调用代码仍然很简单,并且您可以假设您将获得有用的值。如果出现问题,那么你会从代码失败的实际部分得到一条错误消息,而不是默默得到一个undef。如果你调用代码可以做一些恢复失败,那么就可以安排捕获异常,做任何需要的地方。

东西是值得一读的是Exception classes,这是发送额外的信息,调用代码,以及允许它挑就是了哪些异常捕获和它不能处理结构化的方式。你可能不会想在你的代码在任何地方使用他们,但他们是一个有用的技术,当你有一些复杂的,可以在同样复杂的方式失败,并要安排的失败是可以恢复的。

6

模块warn是很烦人的。无论成功还是失败。不要将任何东西打印到终端上,然后继续运行;我的程序无法根据您打印的某条消息采取措施。如果程序可以继续运行,只有在您明确告知它没有问题的情况下才打印消息。如果程序无法继续运行,die。这就是它的目的。

出现问题时总是抛出异常。如果你能解决这个问题,请修复它。如果你不能解决问题,不要尝试;只是抛出异常并让调用者处理它。 (如果你不能处理你打电话的异常,请不要。)

基本上,很多程序都是bug的原因是因为他们试图修复它们无法解决的错误。在出现问题的第一个信号时,干净地死去的程序很容易调试和修复。一旦遇到困惑,程序就会继续运行,只会破坏数据并惹恼所有人。所以不要这样做。尽快死亡。

相关问题