gpt4 book ai didi

Perl 包 : how to import classes into the 'use' r's namespace?

转载 作者:行者123 更新时间:2023-12-04 16:52:49 24 4
gpt4 key购买 nike

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

所以我想做的是将类名的最后一个元素导出到 use 包的命名空间中。 d 异常包。

例如,摘自异常包:

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 东西”之前,我会指出别名专门链接到异常的 throw 方法,所以我不能将它用于非自动-thrown new 调用..)

我试过的一件事是把它放在异常包的 importer 中。 sub( @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 .似乎它有效,但太好了。

我不想导入 NameError进入 main:: !

Typeglobs 和符号表对我来说仍然有点神秘,恐怕。

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

谢谢!

最佳答案

在您的示例中 import子,你是别名包藏匿,这不会做你想做的。相反,您希望使用返回完整包名称的缩短名称创建子例程:

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 *{ ... } .对带有引用的类型团的赋值填充了类型团的那个槽。因此,分配代码引用会安装子例程。

换句话说,以下子程序声明:
sub short () {'a::long::name'}

意思是一样的:
BEGIN {*{__PACKAGE__.'::short'} = sub () {'a::long::name'}}

关于Perl 包 : how to import classes into the 'use' r's namespace?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5124478/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com