Perl包:如何将类导入到';使用';r';名称空间?

Perl包:如何将类导入到';使用';r';名称空间?,perl,exception-handling,namespaces,packages,perl-module,Perl,Exception Handling,Namespaces,Packages,Perl Module,我正在开发一个为其“父”包定义异常的包(使用Exception::Class::Nested)。不过,我不希望父包必须使用非常长的名称,也不希望污染任何其他名称空间 所以我想做的是将类名的最后一个元素导出到包的名称空间中,该包使用异常包 例如,异常包的摘录: package Klass:Foo::Bar::Exceptions; use vars qw( @ISA @EXPORT @EXPORT_OK ... ); @ISA = qw( Klass::Foo::Bar Exporter ); u

我正在开发一个为其“父”包定义异常的包(使用
Exception::Class::Nested
)。不过,我不希望父包必须使用非常长的名称,也不希望污染任何其他名称空间

所以我想做的是将类名的最后一个元素导出到包的名称空间中,该包使用异常包

例如,异常包的摘录:

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!');
我想导出/导入exception类,这样第二次调用(我的$eone)的工作方式就好像
NameError
是在
Klass::Foo::Bar
中定义的一样,但我还没有弄清楚

(在任何人说'but
Exception::Class
具有漂亮的
别名
之前,我要指出,别名专门链接到异常的
throw
方法,因此我不能将其用于非自动抛出的
new
调用..)

我尝试过的一件事是将其放入异常包的
导入器
子部分(
@snames
是一个完全限定的异常类数组(例如,
'Klass::Foo::Bar::Exceptions::namererror'
),或者只是尾部(例如,
'namererror'
):

但这最终要求我使用
Klass::Foo::Bar::namererror
调用异常,而不仅仅是
namererror

我不想将
namererror
导入
main::

恐怕打字珠和符号表对我来说还是有点神秘

我确信有一种方法可以做我想做的事情(或者我正在做一些我不应该做的事情,但现在让我们先别管它)。有人能帮我吗


谢谢!

在您的示例
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'}}

在您的示例
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'}}

我不太清楚它在做什么,但它是有效的。我必须研究它才能理解它。谢谢!!!我不太清楚它在做什么,但它是有效的。我必须研究它才能理解它。谢谢!!!