Throwable::Error 是 Perl 里一个流行的异常基类模块,和 Try::Tiny 或 eval 结合使用,可以让你的代码拥有类似现代语言的异常处理体验。你可以很方便地自定义异常类型,并在代码中用 throw 抛出,然后用 try/catch 捕获。
下面详细介绍 Throwable::Error 的用法,给出几个典型示例:
定义异常类:
package MyApp::Exception;
use parent 'Throwable::Error'; # 继承Throwable::Error
1;
抛出异常:
use MyApp::Exception;
sub may_fail {
my $ok = rand() > 0.5 ? 1 : 0;
MyApp::Exception->throw("失败啦") unless $ok;
return "成功";
}
捕获异常(推荐 Try::Tiny):
use Try::Tiny;
try {
my $result = may_fail();
print "结果: $result\n";
} catch {
warn "捕获到异常: $_"; # $_ 是异常对象
};
你可以给异常对象加自定义属性(比如 code、details):
package MyApp::Exception;
use parent 'Throwable::Error';
sub code { shift->{code} }
sub details { shift->{details} }
1;
抛出异常带属性:
MyApp::Exception->throw(
message => "请求失败",
code => 500,
details => { foo => 'bar' },
);
捕获并读取属性:
try {
...
} catch {
if (eval { $_->isa('MyApp::Exception') }) {
warn "异常信息: " . $_->message;
warn "异常代码: " . $_->code;
warn "详细: " . Dumper($_->details);
} else {
warn "未知异常: $_";
}
};
你可以定义多个异常类,继承自同一个基类:
package MyApp::Exception::Network;
use parent 'Throwable::Error';
1;
package MyApp::Exception::Input;
use parent 'Throwable::Error';
1;
使用和捕获不同类型异常:
try {
if ($something_wrong) {
MyApp::Exception::Network->throw("网络出错");
} elsif ($bad_input) {
MyApp::Exception::Input->throw("输入不合法");
}
} catch {
if (eval { $_->isa('MyApp::Exception::Network') }) {
warn "网络相关异常: $_";
} elsif (eval { $_->isa('MyApp::Exception::Input') }) {
warn "输入相关异常: $_";
} else {
warn "其他异常: $_";
}
};
异常类:
package Cloudflare::DNS::Exception;
use parent 'Throwable::Error';
sub error_code { shift->{error_code} }
sub cf_errors { shift->{cf_errors} }
1;
在模块内部抛出异常:
use Cloudflare::DNS::Exception;
sub create_record {
my ($self, %args) = @_;
my $res = $self->_do_api_request(...);
unless ($res->{success}) {
Cloudflare::DNS::Exception->throw(
message => "Cloudflare API 错误",
error_code => $res->{code},
cf_errors => $res->{errors},
);
}
return $res->{result};
}
调用方处理:
use Try::Tiny;
try {
$dns->create_record(...);
} catch {
if (eval { $_->isa('Cloudflare::DNS::Exception') }) {
warn "CF API异常: " . $_->message;
warn "CF错误码: " . $_->error_code;
warn "CF错误详情: " . Dumper($_->cf_errors);
} else {
warn "未知错误: $_";
}
};
Throwable::Error 也支持老的 eval 风格:
eval {
$dns->create_record(...);
};
if ($@) {
if (eval { $@->isa('Cloudflare::DNS::Exception') }) {
warn "Cloudflare异常: " . $@->message;
} else {
warn "其它异常: $@";
}
}
不过一般推荐 Try::Tiny,更安全。
Throwable::Error 让异常对象化,可携带详细信息,继承易扩展。