Try :: Tiny仍然推荐用于Perl 5.14或更高版本中的exception处理?

Perl社区的共识似乎是Try::Tiny是处理exception的首选方式。

Perl 5.14(这是我使用的版本) 似乎解决了与Try::Tiny地址eval的问题 。 将Try::Tiny仍然为我提供任何好处?

我的回答是不受欢迎的,但是我不认为Perl程序员应该试图在Perl中使用我们称之为“exception”的极其糟糕的概念。 这些本质上是一个旁道返回值。 然而,即使是在使用全局variables传递状态的复杂性的情况下,仍然迷恋于例外的概念,人们仍然试图使其发挥作用。

然而,实际上,人们使用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 ) { ... }; 

这不涉及全局variables,远距离行动,范围头痛,或需要特殊的特殊情况。 您可以创build一个微小的Result类,或者任何你想调用的类来包装你的返回值,这样你就可以得到结构化的数据,而不是没有身份的单个值。 没有更多的想知道什么是回报价值。 这是不是一个真正的价值或失败的迹象? 返回值是否好,如果是定义的,或者是真的? 你的对象可以告诉你这些事情。 而且,你可以使用相同的对象与die 。 如果你已经使用了这个对象并用它作为返回值,那么很less推荐所有额外的东西来容忍$@

我在“返回错误对象而不是抛出exception”

不过,我知道你不能帮助其他人做什么,所以你还得假装Perl有例外。

这总是个人喜好的情况。 你比较喜欢哪个

 my $rv; if (!eval { $rv = f(); 1 } ) { ... } 

要么

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

但是请记住后者使用匿名潜艇,所以它会随着returnnext等等而混乱。 尝试:: Tiny的try-catch可能最终变得复杂得多,因为您在catch块之间添加了沟通渠道。

返回exception的最好的情况(最简单的)是如果$rv在没有exception时总是为true。 它看起来像下面这样:

 my $rv; if ($rv = eval { f() }) { ... return; } 

VS

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

这就是为什么我会使用TryCatch而不是Try :: Tiny来使用这样一个模块。

对Perl的改变仅仅意味着你可以再次执行if ($@) 。 换一种说法,

 my $rv; if (!eval { $rv = f(); 1 } ) { ... } 

可以写

 my $rv = eval { f() }; if ($@) { ... } 

如果没有别的, Try::Tiny仍然是很好的语法糖。 如果你想要一些重量级的东西,还有TryCatch ,它解决了一些与Try::Tiny中的子句是子例程(例如, return没有离开封闭函数)有关的问题。

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

  • 匿名的潜艇 – 里面总是有“ return ”声明的问题
  • 始终抓住一切

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

 try sub {}, catch 'SomeException' => sub {}, catch [qw/Exception1 Exception2/] => sub {}, catch_all sub {}; 

我知道 – 这个语法有点异乎寻常,但是由于明显的' sub ',我们的程序员现在知道' return '语句只是从exception处理程序中退出,而且我们总是只捕捉到我们想要捕捉的exception。

要么做:

 local $@; eval { … } 

…防止对$ @的更改影响全局范围,或使用Try :: Tiny。

在语法上,有些情况下我更喜欢一个或另一个。