Когда я должен использовать `use`? - PullRequest
2 голосов
/ 22 октября 2010

Насколько я помню, всякий раз, когда я использую модуль, в начале моего кода я добавляю строку use.

Недавно я писал два объектных модуля Moose, которые используют друг друга. Посмотрите на этот упрощенный пример:

Один модуль:

package M1 0.001;

use Moose;
use 5.010;
use namespace::autoclean;
# use M2; ### SEE QUESTION BELOW

has 'name' => (
 is       => 'ro',
 isa      => 'Str',
 required => 1,
);

has 'very_cool_name' => (
 is      => 'ro',
 lazy    => 1,
 builder => '_build_very_cool_name',
);

sub _build_very_cool_name {
 my ($self) = @_;
 my $m2 = M2->new( m1 => $self );
 return 'very ' . $m2->cool_name();
}

__PACKAGE__->meta->make_immutable;

1;

Другой модуль: пакет М2 0,001;

use Moose;
use 5.010;
use Data::Dumper;    # TODO DEBUG REMOVE
use namespace::autoclean;
use M1;

has 'm1' => (
 is       => 'ro',
 isa      => 'M1',
 required => 1,
);

sub cool_name {
 my ($self) = @_;
 return 'cool ' . $self->m1->name();
}

__PACKAGE__->meta->make_immutable;

1;

И короткий пример, который их использует:

use strict;
use warnings;
use 5.010;
use M1;
use M2;

my $m1 = M1->new(name => 'dave');
say $m1->very_cool_name();

Теперь обратите внимание, что два модуля используют друг друга. M1 создает экземпляр M2 и использует его для генерации very_cool_name, тогда как M2 имеет экземпляр M1 в качестве атрибута.

Теперь, если я раскомментирую use M2; в M1, мое затмение сходит с ума. Я думаю, это потому, что это цикл, созданный этим «круговым использованием».

Я прокомментировал это use, и все, кажется, работает нормально (я думаю ...), но меня очень беспокоит (я использую объект без use - своего класса! Это «законно»? ..). Это также заставило меня задуматься:

  • Когда мне действительно нужно использовать use? Я думаю, что меня учили всегда использовать его, и, конечно, когда я использую объект.

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

Ответы [ 2 ]

3 голосов
/ 22 октября 2010

С точки зрения Perl это нормально. use достаточно умен, чтобы распознать, что модуль уже загружен, и не загружать его снова. Тем не менее, слабый запах кода должен заставить вас задуматься о том, приемлема ли взаимозависимость, или вам следует реорганизовать код для ее устранения.

Затмение, видимо, не так ярко. Закомментирование одного из операторов use для успокоения редактора , вероятно, сработает, но может создать незначительные ошибки в зависимости от порядка загрузки модулей (приложением) и использования функциональных возможностей друг друга. например если бы M1 были загружены первыми, не use M2 и имели бы блок BEGIN, который требовал функциональности от M2 ... boom! Если ничего не произойдет до времени выполнения (что вероятно), у вас все будет хорошо.

Хотя здесь это не проблема, у вас также могут возникнуть проблемы, если ваш use импортирует символы из другого пакета. В этом случае не удалось удалить use без изменения кода для полной квалификации всех ссылок. (например, звоните MyModule::function() вместо function())

2 голосов
/ 22 октября 2010

Нет причин для M2 до use M1.На самом деле у вас нет рекурсивной зависимости.

Все, что делает M2 - это проверяет имя класса какого-либо объекта, для которого не требуется загрузка M1, и вызывает для него метод, что означает, кто бы ни создавал этот объектзагружен M1.

Ваше правило о необходимости use класса для вызова методов объекта этого класса неверно.use класс, когда вы собираетесь вызывать методы для него напрямую - например, new.(Предполагается, что это чисто ОО-модули, а не вещи, которые экспортируют функции / символы.)

Рассмотрим полиморфизм.Это - особенность , что я могу сделать свой собственный подкласс M1 (называемый, скажем, M1A) и передать его в M2 без того, чтобы M2 ничего не знал о существовании M1A.

...