Подклассы Perl наследуют импортированные модули и прагмы?

Допустим, у вас есть родительский класс Perl в одном файле:

#!/usr/bin/perl
package Foo;
use strict;
use warnings;

use Data::Dumper;

sub new{
    my $class = shift;
    my %self = ();
    return bless %self, $class;
}
1;

и подкласс в другом файле:

#!/usr/bin/perl
package Bar;
use base "Foo";
1;

Будет ли подкласс наследовать операторы использования от родителя? Я знаю, что новый метод будет наследоваться.

В основном я пытаюсь уменьшить количество стандартного кода в моем коде, и я не могу найти четкий ответ на этот вопрос.

10
задан brian d foy 25 September 2010 в 17:39
поделиться

5 ответов

Ах, хороший вопрос!

Will the subclass inherit the use statements from the parent? 

Это зависит от того, что вы подразумеваете под наследованием. Я не буду делать никаких предположений до конца, но ответ будет , может быть, . Видите ли, perl смешивает идеи классов и пространств имен - пакет - это термин, который может описывать любой из них. Теперь проблема заключается в заявлении use , все, что он делает, - это принудительное включение пакета и вызов подпрограммы import () target. Это означает, что он, по сути, имеет неограниченный контроль над вашим пакетом - и, таким образом, над вашим классом.

Теперь добавьте сюда все методы в perl, представляющие собой не что иное, как subs , которые принимают $ self в качестве первого аргумента по соглашению, и вы останетесь с perl5. Это имеет огромные преимущества для тех, кто знает, как им пользоваться. Хотя strict - это лексическая прагма, как насчет Moose ?

package BigMooseUser;
use Moose;

package BabyMooseUser;
our @ISA = 'BigMooseUser';

package Foo;
my $b = BabyMooseUser->new;
print $b->meta->name;

Итак, откуда BabyMooseUser получил конструктор (новый)? Откуда у него мета-класс? Все это обеспечивается одним использованием Moose; в родительском классе (пространстве имен). Итак,

Will the subclass inherit the use statements from the parent?

Что ж, здесь, в нашем примере, если эффекты оператора use заключаются в добавлении методов, то, безусловно.

Это довольно глубокая тема, и это зависит от того, говорите ли вы о прагмах, или более неясных объектных фреймворках, или процедурных модулях. Если вы хотите смягчить влияние родительского пространства имен на ваше собственное в парадигме объектно-ориентированного программирования, см. namespace :: autoclean .

4
ответ дан 3 December 2019 в 20:39
поделиться

Прагматический ответ на вашу проблему: либо используйте, либо посмотрите, как Modern :: Perl делает это для обеспечения строгих требований и предупреждений.

2
ответ дан 3 December 2019 в 20:39
поделиться

Вы спросили в комментарии о Test::Most и о том, как он сокращает кодовую таблицу. Посмотрите на его метод import. Он загружает модули в свое пространство имен, добавляет эти символы в @EXPORT, затем повторно вызывает еще один import через goto, чтобы окончательно ввести их в вызывающее пространство имен. Это какая-то серьезная черная магия, которую применяет Кертис, хотя мне интересно, почему он просто не использовал что-то вроде import_to_level. Может быть, есть какие-то побочные эффекты, о которых я не думаю.


Я довольно много говорю о подобных вещах в Avoid accidently creating methods from module exports в The Effective Perler. Это в другом контексте, но это некоторые из тех же вопросов.

Вот другой пример.

Если какой-то другой модуль загружает модуль, у вас есть к нему доступ. Однако нехорошо зависеть от этого. Вот три отдельных файла:

Top.pm

use 5.010;

package Top;
use File::Spec;

sub announce { say "Hello from top!" }
1;

Bottom.pm

package Bottom;
use parent qw(Top);

sub catfiles { File::Spec->catfile( @_ ) }

1;

test.pl

use 5.010;

use Bottom;

say Bottom->catfiles( qw(foo bar baz) );

say File::Spec->catfile( qw( one two three ) );

Я загружаю File::Spec только в Top.pm. Однако после загрузки я могу использовать его в любом месте моей Perl-программы. Вывод показывает, что я смог "использовать" модуль в других файлах, хотя я загрузил его только в одном:

Bottom/foo/bar/baz
one/two/three

Чтобы это работало, часть кода, которая загружает модуль, должна загрузиться до того, как любая другая часть кода попытается использовать этот модуль. Как я уже сказал, полагаться на это - плохая идея: все сломается, если последовательность загрузки изменится или загружающий модуль исчезнет.

Однако если вы хотите импортировать символы, вы должны явно загрузить нужный вам модуль, находясь в пакете, в который вы хотите импортировать. Это нужно для того, чтобы экспортирующий модуль определил символы в этом пакете. Это не зависит от области видимости.

7
ответ дан 3 December 2019 в 20:39
поделиться

Для уменьшения количества шаблонов у меня есть несколько стратегий: Большинство моих классов - это классы Moose, который заботится о настройке OO, а также предоставляет мне строгие и предупреждающие условия. Если я хочу иметь функции, доступные во многих пакетах, я создаю модуль MyProject::Util, который использует Sub-Exporter для предоставления мне моих собственных функций и моего собственного интерфейса. Это делает его более последовательным, и если я решу изменить Dumper (например) позже по какой-либо причине, мне не придется менять много кода. Это также позволит вам группировать экспорты. Класс обычно выглядит примерно так:

package Foo;
use Moose;
use MyProject::Util qw( :parsing :logging );

use namespace::autoclean;

# class implementation goes here

1;

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

4
ответ дан 3 December 2019 в 20:39
поделиться

Вы можете получить окончательный ответ, изучив таблицы символов для каждого пакета:

# examine-symbol-tables.pl
use Bar;

%parent_names = map{$_ => 1} keys %Foo::;
%child_names = map{$_ => 1} keys %Bar::;

delete $parent_names{$_} && ($common_names{$_} = delete $child_names{$_}) foreach keys %child_names;

print "Common names in symbol tables:\n";
print "@{[keys %common_names]}\n\n";

print "Unique names in Bar symbol table:\n";
print "@{[keys %child_names]}\n\n";

print "Unique names in Foo symbol table:\n";
print "@{[keys %parent_names]}\n\n";

$ perl inherit.pl
Common names in symbol tables:
BEGIN

Unique names in Bar symbol table:
ISA isa import

Unique names in Foo symbol table:
Dumper new VERSION
1
ответ дан 3 December 2019 в 20:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: