使用自定义模块后,在所需文件中定义的子例程分配给错误的命名空间



在我正在编写的脚本中,我有以下类似的内容:

require "environment.pm"; # Various definitions, including subroutine get_coll()
use Custom::Module;
Custom::Module文件中,我从 开始
package Custom::Module;

并以

结尾
1;

当我尝试调用get_coll()时,我得到一个错误:

(main::get_coll())未定义。

如果我需要Custom::Module而不是使用或更改调用为

Custom::Module::get_coll();

可以正常工作。这使我相信CustomModule的"use"语句正在改变"活动"名称空间,因此当get_coll()被处理时(因为它在调用时被处理),它被分配给该名称空间而不是main。这似乎不是常规perl模块的问题,但是从我看过的那些模块中,我没有注意到任何不同,会导致模块加载后名称空间"恢复"回main。如果您能帮助我们更好地理解命名空间的用法或修复模块以避免出现此问题,我们将不胜感激。

旁注:这不是一个大问题,我只是"要求"模块,但它是意外的行为对我来说,所以我主要只是想更好地理解为什么发生了什么。

我试图完全按照您的描述重新创建文件。以下是我的三个源文件

你说

在我正在编写的脚本中,我有以下类似的内容:

require "environment.pm"; # Various definitions, including subroutine get_coll()
use Custom::Module;

当我尝试调用get_coll()时,我得到一个关于它的错误

虽然你没有说你在哪里调用get_coll,我猜它在主脚本中,我认为这相当于这个脚本文件

my_script.pl

use strict;
use warnings;
use 5.010;
require 'environment.pm';
use Custom::Module;
say get_coll();

和这个模块文件

environment.pm

use strict;
use warnings;
use 5.010;
sub get_coll {
  return 'coll';
}
1;

然后输入

Custom::Module文件中,我从 开始
package Custom::Module;

并以

结尾
1;

所以我写了这个模块文件。它没有任何内容因为你没有描述任何

自定义/Module.pm

use strict;
use warnings;
use 5.010;
package Custom::Module;
1;

现在,当我运行my_script.pl时,我得到

coll

没有警告或错误消息,这正是我所期望的

我担心你说environment.pm包含get_coll,但你能够调用Custom::Module::get_collCustom/Module.pm是否也有require 'environment.pm' ?

如果你能指出我对你的描述误解的地方,请指出,因为我目前无法解决你的问题,所以无法帮助你

否则,我建议您使用这三个文件来创建一个简短、独立、正确的问题示例。这将极大地帮助我们为您找到解决方案

您错误地认为requireuse在名称空间子例程定义方面有任何不同。事实并非如此。关于use影响当前包的说法是错误的。

# Custom/Module.pm
package Custom::Module;
# the namespace is now "Custom::Module"
sub foo { ... }  # defines  &Custom::Module::foo
sub bar { ... }  # defines  &Custom::Module::bar
1;   # end of Custom/Module.pm
---
# mainScript.pl
# without an explicit 'package' statement, we are in namespace "main"
use Custom::Module;    # parses Custom/Module.pm
# but when the 'use' statement is complete, we are still in namespace "main"
sub baz { ... }   # defines  &main::baz
$x = baz();       # calls &main::baz
$y = foo();       # calls &main::foo, error if main::foo not defined
$z = Custom::Module::bar();  # calls &Custom::Module::bar
...

注释描述了我们在每个文件的每个部分中的名称空间。如果我们说require Custom::Module而不是use Custom::Module,这些都不会有任何不同。

现在,在没有main::bar()的情况下,一直键入Custom::Module::bar()可能会很麻烦,并且对于您将要引用的bar子程序没有歧义。要使perl将对bar的调用识别为对Custom::Module::bar的引用,关键是将Custom::Module的子例程引用复制到当前名称空间中。也就是说,使main::bar()引用与Custom::Module::bar()相同的子程序。

规范的方法是使用Exporter模块。底层的方法(Exporter在幕后的工作)是操作perl的符号表。

对于您的具体问题,您可以这样使用Exporter:

 # Custom/Module.pm
 package Custom::Module;
 use base 'Exporter';      # make Custom::Module inherit from Exporter
 our @EXPORT = qw(foo bar);
 sub foo { ... }
 sub bar { ... }
 ...
 1;

现在,任何其他调用use Custom::Module的文件都将获得将函数get_coll导入到其命名空间中的方法。这是在Exporter中通过操纵符号表在幕后完成的。具体来说,从包main调用use Custom::Module将使Exporter做出一个typeglob赋值,如

*main::foo = *Custom::Module::foo;

,这将使main::foo()中的函数调用调用Custom::Module::foo()中定义的代码。

最新更新