Як я можу імпортувати глобальні змінні з базового модуля? - perl, успадкування, експорт

Я створив модуль Foo ::Прототип із глобальними змінними $ 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();

Редагувати:

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

Відповіді:

5 за відповідь № 1

Ну, є кілька питань:

  1. Як вказує Брайан, Вашу проблему, мабуть, можна вирішити краще, не використовуючи глобальні змінні. Якщо ви опишете що ви намагаєтесь досягти, а не як, ми можемо дати кращі відповіді.

  2. Якщо ви збираєтеся експортувати речі, вам знадобиться sub import або вам потрібно успадкувати від Exporter. Побачити perldoc Exporter.

  3. Незрозуміло, куди ви бажаєте зателефонувати new відбуватися.

  4. Як Грег вказує в коментарі нижче, змінні оголошені за допомогою my в обсязі пакета не можна експортувати. Тому я заявив $A і $B використовуючи our.

Ось щось, що "працює", але вам доведеться трохи почитати та подумати, перш ніж вирішити, чи так ви хочете піти.

Час на вечір:

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 для відповіді № 2

Фокус у тому, що не потрібно експортувати змінні. Це дуже поганий спосіб програмування.

Можливо, є кращий спосіб досягти того, що ви хочете зробити. Ви просто повинні сказати нам, чому ви намагаєтесь це зробити.


4 для відповіді № 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 :: Сінглтон.