为何Perl会尝试重新加载已载入内存的同名模块?
问题核心原因
use base 的内部实现逻辑决定了它会尝试加载指定父类的模块文件,哪怕内存中已经存在同名包的定义。
具体原理
Perl 全局哈希 %INC 是用来记录已经成功加载的模块的,只有当 %INC 中存在 'A.pm' => 1 这类对应记录时,才会认为 A 模块已经完成加载,不需要再从磁盘读取。
你在测试文件中直接写 package A; 只是在进程符号表中创建了 A 包的命名空间,并没有更新 %INC 哈希,因此 use base 'A' 执行时会判定A模块未加载,触发 require 'A.pm' 逻辑,按照 @INC 路径顺序查找文件,刚好匹配到你项目中自带的 A.pm,而该文件依赖的 Mojo::Base 不在测试环境的依赖中,就触发了报错。
解决方法
如果是自己写测试遇到这类场景,有两种通用方案:
- 改用
parent模块替代base,添加-norequire参数跳过文件加载逻辑:use parent -norequire, 'A'; - 手动标记模块已加载,在你声明完
package A;后添加一行代码:
这行代码会伪装$INC{'A.pm'} = 1;A.pm已经被加载过,base模块就不会再尝试从磁盘读取文件。
如果是安装 Test::Deep 时触发的这个报错,你可以临时将项目自定义的 lib 目录从 @INC 中移除后再执行安装,避免测试用例误加载你本地的同名模块。
内容的提问来源于stack exchange,提问作者Eugen Konkov
相关产品推荐
相关产品推荐

