2

只要我记得,每当我使用模块时,我都会 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?我认为我被教导要始终使用它,当然当我使用一个对象时也是如此。

  • 当两个模块相互使用时,有什么根本上的错误吗(从某种意义上说,每个模块都使用另一个模块的对象;我知道在某些情况下这在逻辑上是不可能的,但有时——比如在这种情况下——我认为这确实是有道理的)。

4

2 回答 2

3

从 Perl 的角度来看,这很好。use足够聪明,可以识别出一个模块已经被加载并且不会再次加载它。也就是说,微弱的代码气味应该让您考虑相互依赖是否可以接受,或者您是否应该重构代码以消除它。

显然,Eclipse 并不那么明亮。注释掉其中一条use语句以安抚编辑器可能会起作用,但可能会产生细微的错误,具体取决于模块(由应用程序)加载的顺序以及它们何时使用彼此的功能。例如,如果首先加载 M1,但没有加载use M2,并且有一个BEGIN块需要 M2 的功能......繁荣!如果在运行时(很可能)之前什么都没有发生,你应该没问题。

虽然这不是问题,但如果您use从另一个包中导入符号,您也会遇到问题。use在这种情况下,如果不更改您的代码以完全限定所有引用,则无法删除。(例如 callMyModule::function()而不是 just function()

于 2010-10-22T14:20:43.160 回答
2

M2没有理由去use M1。你实际上没有递归依赖。

M2 所做的只是验证某个对象的类名——这不需要加载 M1——并在其上调用一个方法——这意味着构建该对象的任何人都加载了 M1。

您关于需要use一个类才能调用该类的对象上的方法的规则是错误的。 use一个类,当你要直接调用它的方法时——例如,new. (这显然是假设纯 OO 模块,而不是导出函数/符号的东西。)

考虑多态性。这是一个功能,我可以创建自己的 M1 子类(例如,称为 M1A)并将其传递给 M2,而 M2 不必知道 M1A 的存在。

于 2010-10-22T15:06:51.297 回答