Как я могу импортировать глобальные переменные из базового модуля? - PullRequest
0 голосов
/ 25 июня 2009

Я создал модуль Foo :: Prototype с глобальными переменными $ A и $ B. Я хочу пакет 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();

Edit:

Я хочу сделать подклассы Foo :: Prototype максимально компактными для других людей. Вместо того чтобы писать $ self -> {A} -> foo (), я бы предпочел, чтобы люди писали $ A-> foo ().

Ответы [ 3 ]

5 голосов
/ 25 июня 2009

Ну, есть несколько вопросов:

  1. Как указывает Брайан , ваша проблема может быть решена лучше без использования глобальных переменных. Если вы опишете что вы пытаетесь достичь, а не как , мы сможем дать лучшие ответы.

  2. Если вы собираетесь экспортировать вещи, вам нужно либо sub import, либо вам нужно наследовать от Exporter. См perldoc Exporter.

  3. Непонятно, где вы хотите, чтобы звонок был new.

  4. Поскольку Greg указывает в комментарии ниже, переменные, объявленные с my в области видимости пакета, не могут быть экспортированы. Поэтому я объявил $A и $B, используя our.

Вот кое-что, что "работает", но вам придется немного почитать и подумать, прежде чем решить, следует ли вам идти этим путем.

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
4 голосов
/ 25 июня 2009

На основании ваших правок $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 .

4 голосов
/ 25 июня 2009

Хитрость в том, чтобы не экспортировать переменные. Это очень плохой способ программирования.

Может быть, есть лучший способ выполнить то, что вы хотите сделать. Вы просто должны сказать нам, почему вы пытаетесь это сделать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...