Perl社区的共识似乎Try::Tiny
是处理异常的首选方法。
Perl的5.14(这是我的版本使用)似乎解决的问题与eval
该Try::Tiny
地址。还会Try::Tiny
为我提供任何好处吗?
Answers:
我的回答是不受欢迎的,但是我不认为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 ) { ... };
这不涉及全局变量,远距离动作,解决头痛问题或不需要特殊内容。您可以创建一个微型类Result
(或任何您想调用的类)来包装返回值,以便拥有结构化数据,而不是没有标识的单个值。毫无疑问,返回值意味着什么。这undef
是真实的价值还是失败的征兆?如果定义了返回值或返回值正确,返回值是否正确?您的对象可以告诉您这些事情。并且,您可以将同一个对象用于die
。如果您已经在使用对象die
并将其用作返回值,则几乎没有建议您要忍受的所有额外工作$@
。
我在“返回错误对象而不是引发异常”中讨论了更多
但是,我知道您无能为力,因此您仍然必须假装Perl有例外。
die
在不应该使用的时候,所以我们仍然需要知道哪种机制可以捕获那些异常。未来的模块设计师,请考虑这种方法!
总是个人喜好。你比较喜欢哪个
my $rv;
if (!eval { $rv = f(); 1 } ) {
...
}
要么
my $rv = try {
f();
} catch {
...
};
但是请记住,后者使用了匿名子,因此与return
,以及next
类似的东西弄混了。Try :: Tiny的try-catch最终可能会变得更加复杂,因为您在catch块与外部之间添加了通信通道。
返回异常的最佳情况(最简单)是,如果$rv
没有异常,则if始终为true。看起来如下:
my $rv;
if ($rv = eval { f() }) {
...
return;
}
与
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 ($@) {
...
}
perl
的内置解析功能。
Try::Tiny
简单轻巧。太容易了。我们有两个问题:
return
内部的' '语句始终存在问题因此,我对进行了一些更改Try::Tiny
,这对我们有所帮助。现在我们有:
try sub {},
catch 'SomeException' => sub {},
catch [qw/Exception1 Exception2/] => sub {},
catch_all sub {};
我知道-这种语法有点奇怪,但是由于有了明显的' sub
',我们的程序员现在知道' return
'语句仅从异常处理程序中退出,并且我们始终只捕获我们要捕获的异常:)
sub{}
perl -MTry::Tiny -E"&try(sub { say 'A'; die qq{B\n} if $ARGV[0] }, &catch(sub { print; }));" 1
Try :: Tiny很不错,但是在最后一个花括号处需要使用半冒号,并且不允许使用异常变量赋值,更不用说捕获异常类了。TryCatch曾经做得很好,但是已被Devel :: Declare的新版本0.006020破坏了。另一个很棒的实现是Syntax :: Keyword :: Try,但是它没有实现异常变量分配或捕获异常类。
有一个新模块Nice :: Try,它是一个完美的替代品。
没有必要在最后一个括号上使用半冒号,例如Try :: Tiny。
您也可以像这样进行异常变量分配
try
{
# something
}
catch( $e )
{
# catch this in $e
}
它也可以使用类异常来工作,例如
try
{
# something
}
catch( Exception $e )
{
# catch this in $e
}
并且它也支持finally
。它的功能集使其非常独特。
全面披露:TryCatch损坏时,我已经开发了此模块。