我第一次尝试Exception :: Class,让我感到惊讶的是,从函数返回时Exception :: Class对象的计算结果为true。不应该默认是相反的。
我知道我可以通过超载来改变它,但我想知道这是不是一个好主意
sub gethtml{
return MyException->new( error => 'some error' );
}
my $response = &gethtml
if($response){
#do something with the html
}
else{
#something went wrong check if it's an exception object
}
答案 0 :(得分:3)
您将异常与返回错误值以表示错误相混淆。
例外的一部分是它们提供了自己的通道来指示错误。这使return
空闲,只返回有效值。无需检查错误与已定义或特殊对象,或者根本不进行任何按功能调用错误检查。这一切都在街区尽头被捕获和处理。
如果你返回一个异常对象,它就会失败;它们不是例外,它们只是错误代码。
要利用异常,示例中的代码应如下所示:
sub get_html {
...try to get the html...
return $html if defined $html;
MyException->throw( error => 'some error' );
}
eval {
my $html = get_html;
# do something with $html;
}
if ( my $e = Exception::Class->caught() ) {
...deal with the error...
}
使用Try::Tiny可以使这更漂亮。
当你必须做很多可能出错的事情时,这会更有意义,例如一堆文件,网络或数据库操作。查看autodie和Path::Tiny等模块,了解其工作原理。
答案 1 :(得分:2)
您不应该使用new
创建一个并将其返回。他们有一个throw
方法,可以自动充当构造函数和die
。
use strict;
use warnings;
use Exception::Class qw( InputException HTTPException );
use Try::Tiny;
sub get_html {
my ($url) = @_;
# input validation
InputException->throw(error => 'no URL') unless $url;
my $res = $ua->get($url);
if ($res->is_success) {
# do more stuff with $res;
} else {
HTTPException->throw( error => 'request failed' );
}
}
# ... later
my $url;
try {
get_html($url);
} catch {
# handle the error which is in $_
if ( $_->isa('InputException') ) {
print "You need to supply a URL";
} elsif ( $_->isa('HTTPException') ) {
print "Could not fetch the HTML because the HTTP request failed.\n";
print "But I am not telling you why.";
}
}
然后你可以去catch
他们(使用Try::Tiny)或者只是将它包装在一个eval中。但基本上这些例外是简单的对象。它们的目的是作为die
的返回值并被抛出,因此无需将它们返回到任何地方。
一旦程序死掉,调用堆栈上的所有作用域都会被强行退出,直到你最终进入eval
块(catch
为止)。在那里,你可以处理错误。而且由于该错误是一个对象,你可以用它做一些奇特的东西。
+--------------------------------------------------------------------+
| sub { |
| +----------------------------------------------------------------+ |
| | if () { | |
| | +------------------------------------------------------------+ | |
| | | foo:: sub { | | |
| | | +--------------------------------------------------------+ | | |
| | | | catch { | | | |
| | | | +----------------------------------------------------+ | | | |
| | | | | doo_stuff:: sub { | | | | |
| | | | | +------------------------------------------------+ | | | | |
| | | | | | | | | | | |
| | | | | | MyException->throw ==> die $obj +---------------------------------+
| | | | | | do_more_stuff(); # never executed | | | | | | |
| | | | | | | | | | | | |
| | | | | +------------------------------------------------+ | | | | | |
| | | | +----------------------------------------------------+ | | | | |
| | | | | | | | |
| | | | handle_exception_in_catch($_) <---------------------------------+
| | | | # ( in Try::Tiny the exception ends up in $_ ) | | | |
| | | | | | | |
| | | +--------------------------------------------------------+ | | |
| | +------------------------------------------------------------+ | |
| +----------------------------------------------------------------+ |
+--------------------------------------------------------------------+
另请参阅Exception::Class文档。
如果您混合例外情况以及常规die
或Carp croak
来电,则在使用->isa
之前,您必须检查是否有人受到祝福。 Safe::Isa在这里派上用场。
use strict;
use warnings;
use Exception::Class qw( InputException HTTPException );
use Try::Tiny;
use Safe::Isa;
sub get_html {
my ($url) = @_;
# input validation
InputException->throw(error => 'no URL') unless $url;
my $res = $ua->get($url);
if ($res->is_success) {
# do more stuff with $res;
die "There is no answer in this HTML" if $res->decoded_content !~ m/42/;
} else {
HTTPException->throw( error => 'request failed' );
}
}
使用此代码,$_->isa('...')
会爆炸,因为die
调用时,$_
不是对象,您无法调用方法isa
未经证实的参考(或非参考)。 Safe :: Isa提供了$_isa
,它首先检查它,否则只返回false
。
my $url;
try {
get_html($url);
} catch {
# handle the error which is in $_
if ( $_->$_isa('InputException') ) {
print "You need to supply a URL";
} elsif ( $_->$_isa('HTTPException') ) {
print "Could not fetch the HTML because the HTTP request failed.\n";
print "But I am not telling you why.";
}
}
有关其工作原理的详细信息,请参阅mst's talk You did what?