Try :: Tiny仍然建议在Perl 5.14或更高版本中进行异常处理吗?

Eug*_*ash 76 perl exception-handling

Perl社区的共识似乎Try::Tiny是处理异常的首选方式.

Perl的5.14(这是我使用的版本)似乎解决问题evalTry::Tiny地址.还会Try::Tiny为我提供任何好处吗?

bri*_*foy 34

我的回答是不受欢迎的,但我不认为Perl程序员应该尝试使用我们在Perl中称为"异常"的极其糟糕的概念.这些基本上是侧通道返回值.然而,仍然迷恋于异常的概念,即使使用全局变量来传递状态的所有复杂性,人们仍然试图使其工作.

然而,实际上,人们会die用来表示失败.有些人会说你可以die使用引用并传回错误对象,但你不需要这样做die.我们有对象,所以我们应该使用对象的所有功能:

 sub some_sub {
    ...
    return Result->new( error => 1, description => ... ) if $something_went_wrong;
    return Result->new( error => 0, ... );
    }

 my $result = some_sub( ... );
 if( $result->is_error ) { ... };
Run Code Online (Sandbox Code Playgroud)

这不涉及全局变量,远距离行动,确定头痛或需要特殊特殊情况.您创建一个小类Result或任何您想要调用它的类来包装返回值,以便您拥有结构化数据而不是没有标识的单个值.再也不知道返回值意味着什么了.这undef是真正的价值还是失败的迹象?如果定义了返回值是否正确,或者它是否为真?你的对象可以告诉你这些事情.并且,您可以使用相同的对象die.如果您已经使用了该对象die并将其用作返回值,则几乎没有什么可以推荐您需要做的额外事情来容忍$@.

我在"返回错误对象而不是抛出异常"中详细讨论了这个问题

但是,我知道你无法帮助其他人做什么,所以你仍然要假装Perl有例外.

  • 很差?我不这么认为.应该在那里处理错误,我们可以说它们如何处理.不应该处理许多错误 - 只是记录,并向用户显示一些消息(这必须在GUI中,而不是在最低级别的函数中).这只是设计假设,并且有一些优点和缺点(像往常一样). (8认同)
  • 非常好的解决方案,但死/异常有一个很大的优势:通过子调用栈传播.我的意思是:不要测试一些子程序调用的通过或失败 - 只是不要捕获异常.它会传播,直到有人抓住它. (6认同)
  • 我可以理解为什么你提出你的论点,但它要求程序员*永远不要忘记检查错误.我们知道他们应该这样做,但是我们应该在理论上做什么以及在紧迫的截止日期之下我们在实践中做些什么并不是一回事.因此,我们可能忘记检查那个*一个*严重错误并让我们的代码继续,轻率地不知道它在各处破坏其数据. (6认同)
  • 我同意,但正如你在最后所说的那样,有些模块在它们不应该"死"时,所以我们仍然需要知道哪种机制来捕获这些异常.未来的模块设计师,考虑这种方法! (2认同)
  • 传播的东西是设计程序的一种非常糟糕的方式.应该处理错误的那些更高级别是什么?在Perl中,你无法处理它并从你离开的地方继续,所以你根本就没有真正处理它.我展示的方法也可以传播.每个级别都可以添加到它获得的结果并传递. (2认同)

ike*_*ami 31

这始终是个人偏好的情况.你比较喜欢哪个

my $rv;
if (!eval { $rv = f(); 1 } ) {
   ...
}
Run Code Online (Sandbox Code Playgroud)

要么

my $rv = try {
   f();
} catch {
   ...
};
Run Code Online (Sandbox Code Playgroud)

但请记住,后者使用anon subs,因此它会混淆return,以及next类似.尝试:: Tiny的try-catch可能会更加复杂,因为你在catch块和它之外添加了通信通道.

返回异常的最佳情况(最简单)场景是if $rv在没有异常时始终为true.它看起来如下:

my $rv;
if ($rv = eval { f() }) {
   ...
   return;
}
Run Code Online (Sandbox Code Playgroud)

VS

my $rv = try {
   f();
} catch {
   ...
};

if (!$rv) {
   return;
}
Run Code Online (Sandbox Code Playgroud)

这就是为什么我会使用TryCatch而不是Try :: Tiny我使用这样的模块.

对Perl的更改只是意味着您可以if ($@)再次执行此操作.换一种说法,

my $rv;
if (!eval { $rv = f(); 1 } ) {
   ...
}
Run Code Online (Sandbox Code Playgroud)

可以写

my $rv = eval { f() };
if ($@) {
   ...
}
Run Code Online (Sandbox Code Playgroud)

  • 如果你不需要捕获eval返回的值(这对我来说至少是最常见的情况) - 那么eval版本变得相当简单. (4认同)

dus*_*uff 14

如果没有别的,Try::Tiny仍然是很好的语法糖.如果你想要一些更重量级的东西,那么也TryCatch可以解决一些与子句中的子句相关的问题Try::Tiny(例如,return不会留下封闭函数).


msz*_*man 10

Try::Tiny简单轻便.太容易了.我们有两个问题:

  • 匿名潜艇 - 里面return的陈述总是存在问题
  • 永远捕捉一切

所以我做了一些改动Try::Tiny,这对我们有所帮助.现在我们有:

try sub {},
catch 'SomeException' => sub {},
catch [qw/Exception1 Exception2/] => sub {},
catch_all sub {};
Run Code Online (Sandbox Code Playgroud)

我知道-这个语法是有点异国情调,但由于明显的" sub",我们的程序员现在知道," return"语句只是从异常处理程序退出,我们始终只捕获这个例外,我们要赶上:)

  • 取决于你对光的意思.在CPU方面,Try :: Tiny损失惨重.另一方面,TryCatch具有更复杂的依赖性. (3认同)
  • 但更重要的是,请注意其他模块(例如[TryCatch](http://search.cpan.org/perldoc?TryCatch))使用实际块,而不是anon subs,以避免噪声. (2认同)
  • @hobbs:当然:)但是如果重新抛出是在没有你参与的情况下......它会好得多;)这里最重要的是捕获所有异常的不同关键字然后只捕获其中的几个:) (2认同)