2010-10-22 2 views
2

Пока я помню, всякий раз, когда я использую модуль, я включаю строку use в начале моего кода.Когда следует использовать `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; 

Другой модуль: пакет M2 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? Я думаю, что меня учили всегда использовать его, и, конечно, когда я использую объект.

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

ответ

2

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

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

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

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

+0

Скажем, я извлекаю сохраненный объект M1 в '$ m1'. Насколько я понимаю из вашего ответа, мне не нужно «использовать M1». Итак, будет ли Perl просто смотреть в моем '@ INC' для' M1.pm', чтобы увидеть, что он должен делать с этим загруженным объектом? –

+0

* 'use' класс, когда вы собираетесь напрямую обращаться к методам - ​​например,' new' * - обратите внимание, что 'M1' вызывает' M2-> new' без 'use M2'. Кажется, что это работает, так что такое «польза» от добавления «использования» здесь? –

+1

@David: повторите свой второй вопрос, если 'M2' уже загружен, то' use M2' ничего не делает (предполагая, что M2 ничего не экспортирует, чего не следует, если это класс OO). Но * вы должны иметь 'M2' уже загружен *, прежде чем пытаться« M2-> новый ». – Ether

3

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

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

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