В Perl, как я могу получить доступ к скаляру, определенному в другом пакете? - PullRequest
3 голосов
/ 07 декабря 2010

Я, похоже, застрял, пытаясь получить доступ к скаляру, который определен в другом пакете, и сузил пример до простого теста, где я могу воспроизвести проблему. То, что я хотел бы сделать, это получить доступ к ссылке на список, который определен в пакете «Пример», с использованием нашего механизма, однако, Dumper показывает, что переменная всегда неопределена в example.pl:

.

Example.pm выглядит следующим образом:

#!/usr/bin/perl -w

use strict;
use warnings;
use diagnostics;

package Example;
use Data::Dumper;

my $exported_array = [ 'one', 'two', 'three' ];
print Dumper $exported_array;

1;

И код, который использует этот пакет, выглядит так:

#!/usr/bin/perl -w

use strict;
use warnings;
use diagnostics;
use Data::Dumper;

use lib '.';
use Example;

{ package Example;
  use Data::Dumper;
  our $exported_array;
  print Dumper $exported_array;
}

exit 0;

После запуска этого кода запускается первый Dumper, и все выглядит нормально, после этого запускается второй Dumper, example.pl, а затем ссылка не определяется:

$VAR1 = [
          'one',
          'two',
          'three'
        ];
$VAR1 = undef;

Ответы [ 4 ]

7 голосов
/ 07 декабря 2010

Объявление my не создает переменную уровня пакета и ничего не вводит в таблицу символов для какого-либо пространства имен.

Чтобы сделать то, что вы пытаетесь сделать, вам нужно изменить объявление в первом файле на

our $exported_array = [ ... ];

Затем вы можете получить к нему доступ в другом файле как

$Example::exported_array
5 голосов
/ 07 декабря 2010

Даже если $exported_array не имеет лексической области действия в пакете Example, Example s $exported_array и main's $exported_array - это две разные вещи.Самый простой способ изменить приведенный вами пример: 1. изменить my на our в объявлении Example и явно указать имя переменной.

our $exported_array;

...

print Dumper $Example::exported_array;

В противном случае вам нужно сделать Example Exporter.(Или просто напишите Example::import подпрограмму - но я не собираюсь это освещать.)

package Example;
our $exported_array = ...;
our @EXPORT_OK = qw<$exported_array>;
use parent qw<Exporter>;

И в сценарии:

use Example qw<$exported_array>;

Однако, как вы можете на самом делеэкспорт массивов (не только ссылки), я бы сделал это:

our @exported_array = (...);
our @EXPORT_OK      = qw<@exported_array>;
...
use Example qw<@exported_array>;
...
print Dumper( \@exported_array );
3 голосов
/ 07 декабря 2010

Когда вы используете оператор my, вы лексически определяете область имени переменной как для области, в которой вы находитесь, так и для файла.

Если вы хотите, чтобы что-то было видимо как квалифицированный массив пакета, вам нужно использовать our, как вы делаете в коде драйвера.Я считаю, что вам также необходимо объявить несколько специальных переменных-экспортеров в файле .pm, но, с другой стороны, вам не нужно объявлять our $exported_array; в файле драйвера.

1 голос
/ 12 декабря 2013

Использование Exporter хорошо для небольших проектов, но если у вас много кода, обрабатывающего данные, которые являются внутренними для модуля, все может стать ... грязным.Объектная ориентация намного удобнее для такого типа вещей.

Почему бы не создать метод для извлечения этих данных?На самом деле, почему бы просто не использовать Moose?

В вашем Example.pm просто загрузить Moose - это дает вам бесплатный конструктор и деструктор, а также подпрограмму для извлечения значений и по умолчанию включен строгий и т. д.Ссылки на массивы должны быть объявлены немного по-другому из-за того, что Class: MOP (движок под рогами Moose) инициализирует атрибуты - вы должны заключить его в ссылку на код (aka sub {}).Вы также должны использовать Data :: Dumper в скрипте, который вызывает пакет, вместо самого пакета.

Example.pm

package Example;
use Moose;

has 'exported_array' => (is => 'rw', default => sub { [ 'one', 'two', 'three' ] });
1;

Затем вызовите это из скрипта:

example.pl

#!/usr/bin/env perl
use Modern::Perl '2013';
use lib '.';
use Example;
use Data::Dumper;

my $example = Example->new;
my $imported_array_ref = $example->exported_array;
my @imported_array = @{$imported_array_ref};
foreach my $element(@imported_array) { say $element; }
say Dumper(\@imported_array);

Я сделал разыменование действительно явным в приведенном выше сценарии example.pl ... это может быть гораздо более кратко, если разыменовать его непосредственно в массиве:

#!/usr/bin/env perl
use Modern::Perl '2013';
use lib '.';
use Example;
use Data::Dumper;

my $example = Example->new;
my @imported_array = @{$example->exported_array};
foreach my $element(@imported_array) { say $element; }
say Dumper(\@imported_array);

Я думаю, что много больше программистов на Perl приняли бы Moose, если бы было больше простых примеров, показывающих, как сделать простые вещи.

Официальное руководство по лосям отлично, но оно действительно написано для тех, кто уже знаком с ООП.

...