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 { ... };
但是请记住后者使用匿名潜艇,所以它会随着return
和next
等等而混乱。 尝试:: 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。
在语法上,有些情况下我更喜欢一个或另一个。