/ / Jak mogę importować zmienne globalne z modułu podstawowego? - perl, dziedziczenie, eksport

Jak mogę zaimportować zmienne globalne z modułu podstawowego? - perl, dziedziczenie, eksport

Stworzyłem moduł Foo ::Prototyp ze zmiennymi globalnymi $ A i $ B. Chcę, aby pakiet Foo :: Bar używał Foo :: Prototype jako bazy do importowania zmiennej globalnej $ A i $ B. Nie mogłem zrozumieć, jak to zrobić.

Rozumiem, że używanie zmiennych globalnych nie jest ogólnie dobrą praktyką, ale w tym przypadku chcę z nich korzystać.

Kod wygląda następująco:

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

Edytować:

Chcę, aby pisanie podklas Foo :: Prototype było jak najmniejsze dla innych osób. Zamiast pisać $ self -> {A} -> foo (), ja raczej pozwalam ludziom pisać $ A-> foo ().

Odpowiedzi:

5 dla odpowiedzi № 1

Cóż, jest kilka problemów:

  1. Tak jak Brian wskazujeTwój problem można prawdopodobnie rozwiązać lepiej bez użycia zmiennych globalnych. Jeśli opisujesz co próbujesz osiągnąć, a nie w jaki sposób, możemy być w stanie zapewnić lepsze odpowiedzi.

  2. Jeśli zamierzasz eksportować rzeczy, albo potrzebujesz sub import lub musisz odziedziczyć z Exporter. Widzieć perldoc Exporter.

  3. Nie jest jasne, gdzie chcesz dzwonić new wystąpić.

  4. Tak jak Greg wskazuje w komentarzu poniżej zmienne zadeklarowane za pomocą my w zakresie pakietu nie można eksportować. Dlatego oświadczyłem $A i $B za pomocą our.

Oto coś, co „działa”, ale musisz zdecydować się na czytanie i myślenie, zanim zdecydujesz, czy tak właśnie chcesz.

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 dla odpowiedzi nr 2

Sztuka polega na tym, że nie trzeba eksportować zmiennych. To bardzo zły sposób na programowanie.

Może jest lepszy sposób na osiągnięcie tego, co chcesz zrobić. Musisz tylko powiedzieć nam, dlaczego próbujesz to zrobić.


4 dla odpowiedzi nr 3

Na podstawie Twojej edycji $A i $B zostanie użyty do wywołania metod.

Zakładam więc, że są to obiekty singleton przechowywane jako dane klasy dla klasy bazowej.

Jeśli narazisz je na zmienne, można je łatwo zmienić i mogą wystąpić różnego rodzaju problemy.

Dlaczego nie użyć akcesorium?

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

Ale wszystko to wydaje się bardzo męczące.

Aby rozwiązać ten problem w moim kodzie, użyłbym Moose, a następnie stworzyłem rolę do wprowadzenia metod związanych z A i 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;
}

}

Jeśli chcesz, aby Thing1 i Thing2 były singletonami, użyj MooseX :: Singleton.