Perl 如何从基本模块导入全局变量?

Perl 如何从基本模块导入全局变量?,perl,inheritance,export,Perl,Inheritance,Export,我创建了一个带有全局变量$a和$B的模块Foo::Prototype。我想要一个包Foo::Bar,它使用Foo::Prototype作为基础来导入全局变量$a和$B。我想不出怎么做 我知道使用全局变量通常不是一个好的实践,但在这种情况下,我想使用它们 代码如下所示: package Foo:Prototype; my ($A, $B); our @EXPORT = qw($A $B); sub new { [...] $A = 1; $B = 2; } 1; pa

我创建了一个带有全局变量$a和$B的模块Foo::Prototype。我想要一个包Foo::Bar,它使用Foo::Prototype作为基础来导入全局变量$a和$B。我想不出怎么做

我知道使用全局变量通常不是一个好的实践,但在这种情况下,我想使用它们

代码如下所示:

package Foo:Prototype;
my ($A, $B);
our @EXPORT = qw($A $B);

sub new {
    [...]
    $A = 1;
    $B = 2;
}

1;

package Foo:Bar;
use base Foo:Prototype qw($A $B);

sub test {
    print $A, "\n";
    print $B, "\n";
}

1;


# test.pl
Foo:Bar->new();
Foo:Bar->test();
编辑:

package T;
use strict;
use warnings;

use base 'Exporter';

our ($A, $B);
our @EXPORT = qw($A $B);

sub new {
    $A = 1;
    $B = 2;
}

"EOF T.pm"
package U;

use strict;
use warnings;

use base 'T';
use T;

sub test {
    my $self = shift;
    print "$_\n" for $A, $B;
}

"EOF U.pm"
#!/usr/perl/bin
use strict;
use warnings; 

use U;

U->new;
U->test;

C:\Temp> t.pl
1 
2

我想让编写Foo::Prototype的子类对其他人来说尽可能紧凑。与其写$self->{A}->foo(),我宁愿让人们写$A->foo()

  • 因此,如果不使用全局变量,您的问题可能会得到更好的解决。如果您描述您试图实现的目标,而不是如何实现,我们可能会提供更好的答案

  • 如果要导出内容,则需要一个子导入,或者需要从导出器继承。看

  • 不清楚要在何处调用
    new

  • 正如下面的注释所指出的,在包范围内用
    my
    声明的变量无法导出。因此,我使用
    our
    声明了
    $A
    $B

  • 这是一个“有效”的方法,但在决定这是否是你想要的方法之前,你必须先阅读和思考一下

    T.pm:

    package T;
    use strict;
    use warnings;
    
    use base 'Exporter';
    
    our ($A, $B);
    our @EXPORT = qw($A $B);
    
    sub new {
        $A = 1;
        $B = 2;
    }
    
    "EOF T.pm"
    
    package U;
    
    use strict;
    use warnings;
    
    use base 'T';
    use T;
    
    sub test {
        my $self = shift;
        print "$_\n" for $A, $B;
    }
    
    "EOF U.pm"
    
    #!/usr/perl/bin
    use strict;
    use warnings; 
    
    use U;
    
    U->new;
    U->test;
    
    C:\Temp> t.pl
    1 
    2
    
    U.pm:

    package T;
    use strict;
    use warnings;
    
    use base 'Exporter';
    
    our ($A, $B);
    our @EXPORT = qw($A $B);
    
    sub new {
        $A = 1;
        $B = 2;
    }
    
    "EOF T.pm"
    
    package U;
    
    use strict;
    use warnings;
    
    use base 'T';
    use T;
    
    sub test {
        my $self = shift;
        print "$_\n" for $A, $B;
    }
    
    "EOF U.pm"
    
    #!/usr/perl/bin
    use strict;
    use warnings; 
    
    use U;
    
    U->new;
    U->test;
    
    C:\Temp> t.pl
    1 
    2
    
    t.pl:

    package T;
    use strict;
    use warnings;
    
    use base 'Exporter';
    
    our ($A, $B);
    our @EXPORT = qw($A $B);
    
    sub new {
        $A = 1;
        $B = 2;
    }
    
    "EOF T.pm"
    
    package U;
    
    use strict;
    use warnings;
    
    use base 'T';
    use T;
    
    sub test {
        my $self = shift;
        print "$_\n" for $A, $B;
    }
    
    "EOF U.pm"
    
    #!/usr/perl/bin
    use strict;
    use warnings; 
    
    use U;
    
    U->new;
    U->test;
    
    C:\Temp> t.pl
    1 
    2
    

    诀窍是不必导出变量。这是一种非常糟糕的编程方式


    也许有更好的方法来完成你想做的事情。您只需告诉我们您为什么要这样做。

    根据您的编辑,
    $A
    $B
    将用于调用上的方法

    因此,我假设它们是作为基类的类数据存储的单例对象

    如果将它们作为变量公开,它们很容易被更改,并且可能会出现各种问题

    为什么不使用访问器呢

    package Foo::Proto;
    
    my $A;
    my $B;
    
    sub A {
       return $A;
    }
    
    sub B {
       return $B;
    }
    
    package Foo::Child;
    our @ISA= qw(Foo::Prototype);
    
    sub test {
        my $self = shift;
    
        $self->A->blah();
    
        # Or if I am doing many things with A, and want to type less:
        my $A = $self->A;
        $A->blah();   
    }
    
    package Foo::Kid;
    our @ISA= qw(Foo::Prototype);
    
    # If you will never change $A in the prototype, you could do this:
    my $A = __PACKAGE__->A;
    
    sub test {
      $A->blah();
    }
    
    但这一切似乎都是胡闹

    为了在我的代码中解决这个问题,我将使用Moose,然后创建一个角色来引入与a和B相关的方法

    my $m = Foo::Mooseling->new();
    $m->test_A();
    $m->test_B();
    
    
    BEGIN {  # This is going to be $A, I needed something to call $A->foo on.
        package Thing1;  
        sub new  { bless {}, __PACKAGE__; }
        sub foo  { print __PACKAGE__."::foo()\n"; }
        sub blah { print __PACKAGE__."::blah()\n"; }
    }
    BEGIN {  # This is going to be B. It is not interesting either.
        package Thing2;
        sub new  { bless {}, __PACKAGE__; }
        sub bar  { print __PACKAGE__."::bar()\n"; }
        sub bluh { print __PACKAGE__."::bluh()\n"; }
    }
    
    # This is the interesting part:    
    BEGIN {  # This ROLE will provide A and B methods to any objects that include it.
        package Foo::ProtoMoose;
        use Moose::Role;
    
        has 'A' => (
            is => 'ro',
            isa => 'Thing1',
            handles => [qw( foo blah )],  # Delegate calls to foo and blah for consuming object to this A.
            default => sub { Thing1->new(); }, # Create a Thing1 to be A.
        );
    
        has 'B' => (
            is => 'ro',
            isa => 'Thing2',
            handles => [qw( bar bluh )],       
            default => sub { Thing2->new(); },
        ); 
    }
    
    BEGIN {  # This method consumes the ProtoMoose Role.
        package Foo::Mooseling;
        use Moose;
    
        with 'Foo::ProtoMoose';
    
        sub test_A {
            my $class = shift;
    
            $class->foo;
            $class->blah;
        }
    
        sub test_B {
            my $class = shift;
    
            $class->bar;
            $class->bluh;
        }
    
    }
    

    如果你想让Thing1和Thing2成为单例,那么就使用。

    好答案。你含蓄地报道了它,但我要强调的是,Exporter不会导出词汇。@SinanÜnür:这是一篇老文章,我已经有一段时间没有讨论过导出了。你能解释一下为什么
    使用T
    在U.pm中将其用作基础后是必需的?@vol7ron Correction:For
    $a
    $B
    要导出到包
    U
    。我不打算使用它,但我很感兴趣,希望
    base
    默认情况下能够处理导入。有趣。@vol7ron base:在编译时与基类建立ISA关系。