Домены 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;
Будет ли подкласс наследовать операторы использования от родителя? Я знаю, что новый метод будет унаследован.
В основном я пытаюсь уменьшить количество шаблонов в моем коде, и я не могу найти четкого ответа на этот вопрос.
Ответы
Ответ 1
А, хороший вопрос!
Will the subclass inherit the use statements from the parent?
Хорошо, это зависит от того, что вы подразумеваете под наследованием. Я не буду делать никаких предположений до конца, но, может быть, ответ. Видите ли, perl смешивает идеи Classes
, а Namespaces
- a package
- это термин, который может описывать любой из них. Теперь проблема заключается в утверждении use
все, что она делает, это принудительное включение пакета и вызов целевых import()
sub. Это означает, что он по существу имеет неограниченный контроль над вашим пакетом - и тем самым ваш класс.
Теперь составьте это, когда все методы в perl будут не более чем subs
, которые принимают $self
как первый аргумент по соглашению, и вы остаетесь с perl5. У этого есть огромный потенциал для тех, кто знает, как его использовать. Хотя строгая лексическая прагма, а что насчет Moose
?
package BigMooseUser;
use Moose;
package BabyMooseUser;
our @ISA = 'BigMooseUser';
package Foo;
my $b = BabyMooseUser->new;
print $b->meta->name;
Теперь, где BabyMooseUser
получил конструктор (новый) из? Откуда у него мета-класс? Все это предоставляется из одного use Moose;
в родительском классе (пространство имен). Так
Will the subclass inherit the use statements from the parent?
Ну, здесь, в нашем примере, если эффекты инструкции use должны добавлять методы, чем, конечно.
Этот предмет довольно глубокий, и это зависит от того, говорите ли вы о прагмах или о более неясных объектных рамках или процедурных модулях. Если вы хотите, чтобы пространство имен родителей влияло на ваши собственные в парадигме OO, см. namespace::autoclean
.
Ответ 2
Вы спросили в комментарии о Test:: Most и о том, как он уменьшает шаблон. Посмотрите на его метод import
. Он загружает модули в свое пространство имен, добавляя эти символы в @EXPORT
, а затем повторно вызывающий другой import
через goto
, чтобы, наконец, получить их в вызывающее пространство имен. Это какая-то серьезная черная магия, которую Куртис продолжает там, хотя мне интересно, почему он просто не использовал что-то вроде import_to_level. Возможно, есть некоторые побочные эффекты, о которых я не думаю.
Я немного об этом говорю в Избегайте случайного создания методов из экспорта модулей в Эффективный 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
Чтобы это сработало, часть кода, загружающего модуль, должна загружаться, прежде чем какая-либо другая часть кода попытается использовать этот модуль. Как я уже сказал, это плохая идея, чтобы зависеть от этого: вещи ломаются, если последовательность загрузки изменяется или модуль загрузки исчезает.
Если вы хотите импортировать символы, вы должны явно загрузить модуль, который хотите, пока вы находитесь в пакете, который хотите импортировать. Это так, что модуль экспорта определяет символы в этом пакете. Это не то, что зависит от объема.
Ответ 3
Для сокращения шаблонов у меня есть несколько стратегий: большинство моих классов Moose классы, которые заботятся о настройке OO а также дает мне строгие предупреждения. Если я хочу иметь функции, доступные во многих пакетах, я создам специальный проект MyProject::Util
, который использует Sub-Exporter, чтобы предоставить мне с моими собственными функциями и с моим собственным интерфейсом. Это делает его более последовательным, и если я по какой-то причине решил изменить Дампер (например), мне не нужно менять много кода. Это также позволит вам группировать экспорт. Класс обычно выглядит примерно так:
package Foo;
use Moose;
use MyProject::Util qw( :parsing :logging );
use namespace::autoclean;
# class implementation goes here
1;
Если есть другие вещи, которые вы считаете шаблонами и хотите упростить их включение, это, конечно, зависит от того, что это за вещи.
Ответ 4
Прагматичный ответ на вашу проблему: либо используйте, либо посмотрите, как Modern::Perl
делает это для соблюдения строгих правил и предупреждений.
Ответ 5
Вы можете получить окончательный ответ, просмотрев таблицы символов для каждого пакета:
# 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