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

时间:2009-06-24 21:58:29

标签: perl inheritance export

我使用全局变量$ A和$ B创建了一个模块Foo :: Prototype。我想要使​​用Foo :: Prototype作为基础来导入全局变量$ A和$ B的包Foo :: Bar。我无法想象如何做到这一点。

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

代码如下所示:

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();

修改

我想让其他人尽可能地为Foo :: Prototype编写子类。我不想写$ self-> {A} - > foo(),而是让人们写$ A-> foo()。

3 个答案:

答案 0 :(得分:5)

嗯,有一些问题:

  1. 作为brian points out,您可以在不使用全局变量的情况下更好地解决问题。如果您描述的是 ,而不是 ,我们可能会提供更好的答案。

  2. 如果您要导出内容,则需要sub import或者需要继承Exporter。请参阅perldoc Exporter

  3. 目前尚不清楚您希望调用new的位置。

  4. 正如Greg在下面的评论中指出的那样,无法导出在包范围内使用my声明的变量。因此,我使用$A声明$Bour

  5. 这是“有效”的东西,但在决定这是否是您想要的方式之前,您将不得不做一些阅读和思考。

    <强> 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"
    

    <强> U.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"
    

    <强> t.pl:

    #!/usr/perl/bin
    use strict;
    use warnings; 
    
    use U;
    
    U->new;
    U->test;
    
    C:\Temp> t.pl
    1 
    2
    

答案 1 :(得分:4)

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

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

答案 2 :(得分:4)

根据您的修改,$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成为单身,请使用MooseX::Singleton