使用Exception::Class,我可以將例外定義為類,一旦它們被加載到任何地方,它們就可以在任何地方使用。但是現在很多地方都推薦使用,包括 E::C 本身的檔案Throwable。
Throwable是一個角色,所以我需要構建類來組合它。Throwable::Factory對此有所幫助,但我無法弄清楚如何使這些類隨處可用。似乎 T::F 構建了回傳不透明類名的子例程。我覺得我錯過了最后一塊拼圖,但還沒有找到 T::F 實際使用的任何例子。
uj5u.com熱心網友回復:
一種想法可能是在單獨的模塊中收集例外并將其匯入到需要訪問例外的所有模塊中。不幸的是,由于某種原因,似乎很難匯出這些。我嘗試了以下(MyExceptions.pm):
package MyExceptions;
use Throwable::Factory
GeneralException => undef,
RuntimeException => undef,
;
our @EXPORT = qw(GeneralException RuntimeException);
sub import2 {
no strict 'refs';
my $caller = caller;
my $pkg = __PACKAGE__;
for my $name (@EXPORT) {
my $imported = $caller . '::' . $name;
my $coderef = *{$pkg . "::" . $name};
*{ $imported } = \*{ $coderef };
}
}
sub import {
no strict 'refs';
my $caller = caller;
my $pkg = __PACKAGE__;
my @coderefs = (
["GeneralException", *MyExceptions::GeneralException],
["RuntimeException", *MyExceptions::RuntimeException]
);
for my $item (@coderefs) {
my ($name, $coderef) = @$item;
my $imported = $caller . '::' . $name;
*{ $imported } = \*{ $coderef };
}
}
1;
我無法使import2()出口sub在上面的代碼作業(它不會匯出例外,但別的東西(但什么?)),所以作為一種解決方法我寫的import()這些作品分。
uj5u.com熱心網友回復:
我似乎在尋找 4 件事。
- 宣告例外型別的簡單語法。
- 實作 Throwable 的例外。
- 例外物件中的額外功能,例如標簽、自定義屬性以及將屬性傳遞給建構式的簡化。
- 通過類(全域可用)而不是函式(必須匯入到每個模塊中)來實體化例外。
像Exception::Class,Throwable::Factory并Throwable::SugarFactory提供了用于宣告例外型別的精簡語法,但事實證明我可以沒有它。Throwable::Factory實際上擁有我想要的一切,除了例外函式必須在它們使用的同一個檔案中宣告。它們是一種可一次性拋出的例外。我不想要那個。
Throwable::Factory例外中的一些額外功能來自 Throwable::Error,它是Throwable發行版的一部分。其余的很容易偷。Throwable::Error 實際上是一個Moo類,所以我們有一個贏家。
我可以將所有例外類放在一個檔案中,并通過use我的應用程式頂部加載它。例外層次繼承自 Throwable::Error 作為基類。因為這些是 Moo 類,所以向特定類添加自定義訪問器是微不足道的。我可以從 Throwable::Factory 中剪切/粘貼我喜歡的額外功能。
package MyApp::Exceptions ;
use strict ;
use warnings ;
use Throwable::Error ;
use Types::Standard qw( Str ) ;
use Moo ;
use namespace::clean ;
use feature qw(signatures) ;
no warnings qw(experimental::signatures) ;
extends 'Throwable::Error' ;
with 'Role::Identifiable::HasTags' ;
has description => (
is => 'ro',
isa => Str,
required => 1,
default => 'Generic exception',
) ;
# stack_trace() and message() inherited from Throwable::Error
sub error ($self) { $self->message }
sub package ($self) { $self->stack_trace->frame(0)->package }
sub file ($self) { $self->stack_trace->frame(0)->filename }
sub line ($self) { $self->stack_trace->frame(0)->line }
# sugar for ::HasTags
sub has_tags ( $self, @wanted ) {
$self->has_tag($_) || return 0 for @wanted ;
return 1 ;
}
# support shorthand instantiation eg Foo->throw($message, attr => $val);
around BUILDARGS => sub {
my ( $orig, $class, @args ) = @_ ;
return {} unless @args ;
return $class->$orig(@args) if @args == 1 ;
unshift @args, 'message' if @args % 2 ;
return $class->$orig( {@args} ) ;
} ;
# ----- enduser exception classes -----
package SystemError ;
use Types::Standard qw( Int ) ;
use Moo ;
extends 'MyApp::Exceptions' ;
has code => ( is => 'ro', isa => Int->where('$_ >= 0'), default => 1 ) ;
has ' description' => ( default => 'A system error' ) ;
package FileError ;
use Types::Standard qw( InstanceOf ) ;
use Moo ;
extends 'SystemError' ;
has ' code' => ( default => 2 ) ;
has ' description' => ( default => 'A file error' ) ;
has file => ( is => 'ro', required => 1, isa => InstanceOf['Path::Tiny'] ) ;
1 ;
只要在某處,我已經說過use MyApp::Exceptions;,現在我可以在任何地方說:
use Nice::Try ;
try {
something() or SystemError->throw("Problem trying to do something",
code => 7,
tags => [qw(something broke)],
) ;
}
catch ( SystemError $e where { $_->has_tags(qw(something broke)) }) {
fix_it($e) ;
}
catch ( SystemError $e where { $_->has_tag('something') }) {
repair_it($e) ;
}
catch ( FileError $e ) {
warn sprintf "Problem doing something() with file %s: %s",
$e->file->basename, $e->message ;
}
catch ( $e ) {
die "Give up! $e" ;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/351489.html
