【问题标题】:How can I import global variables from a base module?如何从基本模块导入全局变量?
【发布时间】:2010-11-05 16:31:57
【问题描述】:

我用全局变量 $A 和 $B 创建了一个模块 Foo::Prototype。我想要使​​用 Foo::Prototype 作为基础的包 Foo::Bar 来导入全局变量 $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();

编辑:

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

【问题讨论】:

    标签: perl inheritance export


    【解决方案1】:

    嗯,有几个问题:

    1. 作为brian points out,您的问题可能可以在不使用全局变量的情况下得到更好的解决。如果您描述您想要实现的目标而不是如何,我们或许能够提供更好的答案。

    2. 如果你要导出东西,你要么需要sub import,要么需要继承Exporter。见perldoc Exporter

    3. 不清楚您希望在哪里调用new

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

    这里有一些“有效”的东西,但在决定这是否是你想要的方式之前,你必须做一些阅读和思考。

    下午:

    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"
    

    t.pl:

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

    【讨论】:

    • 不错的答案。您隐含地介绍了它,但我要强调的是,Exporter 不会导出词汇。
    • @SinanÜnür:这是一篇旧帖子,我已经有一段时间没有处理出口了。你能解释一下为什么use T; 在作为 U.pm 的基地之后是必要的吗?
    • @vol7ron 更正:对于要导出到包中的$A$B U
    • 我不打算使用它,但我很感兴趣并且希望base 默认处理导入。很有趣。
    • @vol7ron base: 在编译时与基类建立 ISA 关系
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      根据您的编辑,$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

      【讨论】:

        猜你喜欢
        • 2021-12-14
        • 2018-11-21
        • 1970-01-01
        • 1970-01-01
        • 2017-08-28
        • 1970-01-01
        • 2014-02-18
        • 2021-01-27
        相关资源
        最近更新 更多