首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么perl在已经加载模块时尝试重新加载它?

为什么perl在已经加载模块时尝试重新加载它?
EN

Stack Overflow用户
提问于 2021-07-17 11:16:55
回答 1查看 93关注 0票数 1

我试图将Carton安装到我的项目的本地目录中,得到了错误:

代码语言:javascript
复制
--> Working on Test::Deep
Fetching...
...
t/isa.t ..................... Can't locate Mojo/Base.pm in @INC (you may need to install the Mojo::Base module) (@INC contains: CODE(0x557913d006d0) t/lib /home/kes/.cpanm/work/1626520042.29670/Test-Deep-1.130/blib/lib /home/kes/.cpanm/work/1626520042.29670/Test-Deep-1.130/blib/arch /home/kes/work/projects/tucha/monkeyman/local/lib/perl5/x86_64-linux /home/kes/work/projects/tucha/monkeyman/local/lib/perl5 /home/kes/work/projects/tucha/monkeyman/lib /home/kes/perl5/perlbrew/perls/perl-5.35.1/lib/site_perl/5.35.1/x86_64-linux /home/kes/perl5/perlbrew/perls/perl-5.35.1/lib/site_perl/5.35.1 /home/kes/perl5/perlbrew/perls/perl-5.35.1/lib/5.35.1/x86_64-linux /home/kes/perl5/perlbrew/perls/perl-5.35.1/lib/5.35.1 CODE(0x557913d00670) .) at /home/kes/work/projects/tucha/monkeyman/lib/A.pm line 2.
BEGIN failed--compilation aborted at /home/kes/work/projects/tucha/monkeyman/lib/A.pm line 2.
Compilation failed in require at /home/kes/perl5/perlbrew/perls/perl-5.35.1/lib/5.35.1/base.pm line 138.
    ...propagated at /home/kes/perl5/perlbrew/perls/perl-5.35.1/lib/5.35.1/base.pm line 160.
BEGIN failed--compilation aborted at t/isa.t line 133.

发生此错误是因为我的应用程序有A模块,但是t/isa.t已经定义了自己的package A,该package A已经加载到内存中。

代码语言:javascript
复制
# Test::Deep:t/isa.t:120
package A;

use Test::Deep;
@A::ISA = qw( Test::Deep );

{
  ::ok(A->isa("Test::Deep"), "U::isa says yes");
  ::ok(! A->isa("Test"), "U::isa says yes");
}


{
  package C;
  use base 'A';    # <<<< this cause error
}

但是,为什么use base 'A'试图在package A已经加载到内存时从磁盘重新加载包A呢?

perl -v 5.35.1

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-07-17 12:25:31

您正在体验包和模块之间的差异。包是一个命名空间。模块是一个文件。很容易混淆它们,因为按照约定,Foo::Bar::Baz命名空间的定义将在文件Foo/Bar/Baz.pm中。

当你写:

代码语言:javascript
复制
use Foo::Bar::Baz;

Perl将其解释为两个指令:

如果没有加载

  1. 加载文件Foo/Bar/Baz.pm
  2. 调用Foo::Bar::Baz命名空间上的方法import

( use base 'Foo::Bar::Baz'也做了类似的事情,除了#2之外,它在继承方面做了一些奇怪的事情。)

因此,在您的例子中,当您执行use base 'A'时,Perl将执行#1,除非文件A.pm已经加载。是的,您已经在A命名空间中定义了一些内容,但这并不重要。

给你一些不同的解决方案。

让Perl以为A.pm已经加载了

use base 'A'之前添加这一行将使Perl以为A.pm已经加载。

代码语言:javascript
复制
BEGIN { $INC{'A.pm'} = __FILE__ };

使用父级

这样做,而不是use base 'A'

代码语言:javascript
复制
use parent '-norequire', 'A';

parent是更现代的base版本,有一个跳过步骤1的-norequire选项。

不要使用基或父

所有这些模块都在为您设置@ISA变量。你可以自己去做。

代码语言:javascript
复制
{
  package C;
  our @ISA = 'A';
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68420020

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档