我正在开发一个为其“父”包定义异常(使用Exception::Class::Nested
)的包。我不希望父包必须使用真正长的名称,但和我不想污染任何其他名称空间。
所以我想做的是将类名的最后一个元素导出到use
异常包的包的名称空间中。
例如,异常包的摘录:
package Klass:Foo::Bar::Exceptions;
use vars qw( @ISA @EXPORT @EXPORT_OK ... );
@ISA = qw( Klass::Foo::Bar Exporter );
use Exception::Class::Nested 0.04 (
'Klass::Foo::Bar::Exceptions::BaseClass' => {
description => 'Base class for exceptions',
'Klass::Foo::Bar::Exceptions::NameError' => {
error => "I don't like your face"
}
}
);
'父'包:
package Klass::Foo::Bar;
use Klass::Foo::Bar::Exceptions;
Klass::Foo::Bar::Exceptions::NameError->throw(error => "D'oh!");
my $e = NameError->new(error => 'Mwahaha!');
我喜欢导出/导入异常类,以便第二次调用(my $e
一次)就好像NameError
中定义了Klass::Foo::Bar
一样但是我还没弄明白。
(在有人说'但Exception::Class
有漂亮的alias
之前'之前,我会指出别名是专门与异常{{{ 1}}方法,所以我不能将它用于非自动抛出的throw
调用..)
我尝试过的一件事是将它放在异常包中new
sub importer
是一个完全限定的异常类的数组(例如,{{1 }或者只是尾端(例如,@snames
):
'Klass::Foo::Bar::Exceptions::NameError'
但最终要求我使用'NameError'
而不仅仅my $caller = caller();
$caller ||= 'main';
my @snames = @{$EXPORT_TAGS{exceptions}};
for my $exc (@snames) {
$exc =~ s/^.*:://;
no strict qw(subs refs);
*{"${caller}\:\:${exc}\:\:"} = \*{__PACKAGE__ . "\:\:${exc}\:\:"};
}
来调用异常。它似乎有效,但太好了。
我 想要将Klass::Foo::Bar::NameError
导入NameError
!
对我来说,Typeglobs和符号表仍然有点神秘,我很害怕。
我确信有一种方法可以做我想要的事情(或者我正在做一些我不应该完全做的事情,但是让我们暂时离开它)。任何人都可以帮我这个吗?
谢谢!
答案 0 :(得分:5)
在您的示例import
sub中,您正在对包存储器进行别名处理,这将无法执行您想要的操作。相反,您希望创建具有返回完整包名称的缩写名称的子例程:
sub import {
my $caller = caller;
for my $long (@{$EXPORT_TAGS{exceptions}}) { # for each full name
my ($short) = $long =~ /([^:]+)$/; # grab the last segment
no strict 'refs';
*{"$caller\::$short"} = sub () {$long}; # install a subroutine named
# $short into the caller's pkg
# that returns $long
}
}
分开最后一行,sub () {$long}
创建一个不带参数的匿名子程序。代码引用包含单个变量$long
,它保留循环迭代期间的值。这称为词法闭包,这基本上意味着只要子例程,子例程的编译环境($long
及其值)将持续存在。
然后使用$short
名称将此匿名子例程安装到调用者的包中。调用者包中子例程的完全限定名称为caller::subname
,"$caller\::$short"
构造。然后将其取消引用为typeglob *{ ... }
。使用引用分配给typeglob填充typeglob的那个槽。因此,分配代码引用会安装子例程。
换句话说,以下子程序声明:
sub short () {'a::long::name'}
与以下内容相同:
BEGIN {*{__PACKAGE__.'::short'} = sub () {'a::long::name'}}