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

Subroutines defined in required file assigned to wrong namespace after use of custom module

在我正在处理的脚本中,我有类似于以下内容的内容:

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

Custom::Module 文件中,我从

开始
package Custom::Module;

并以

结尾
1;

当我尝试调用 get_coll() 时出现错误:

( main::get_coll() ) being undefined.

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

Custom::Module::get_coll();

它工作正常。这让我相信 CustomModule 的 "use" 语句正在改变 "active" 命名空间,所以当 get_coll() 被处理时(因为它是在调用时处理的)它被分配给那个命名空间而不是 main。这似乎不是常规 perl 模块的问题,但从我浏览过的模块来看,我没有注意到任何不同之处会导致命名空间 "revert" 在模块加载后返回到 main .如果能更好地理解命名空间的使用或修复模块以防止出现此问题,我们将不胜感激。

旁注:"require" 模块对我来说不是什么大问题,但这对我来说是意想不到的行为,所以我主要只是想更好地理解为什么会发生这种情况。

您误认为 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,其中的 None 会有任何不同。

现在,当没有 main::bar() 时,一直输入 Custom::Module::bar() 可能会很麻烦,而且您将指的是哪个 bar 子例程也没有歧义。让 perl 将对 bar 的调用识别为引用 Custom::Module::bar 的关键是将子例程引用从 Custom::Module 复制到当前名称空间中。也就是说,使 main::bar() 引用与 Custom::Module::bar().

相同的子例程

执行此操作的规范方法是使用 Exporter 模块。执行此操作的低级方法(以及 Exporter 在幕后所做的事情)是操纵 perl 的符号 tables.

对于您的具体问题,您可以像这样使用 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 中通过操纵符号 table 在幕后完成的。具体来说,从包 main 调用 use Custom::Module 将得到 Exporter 来进行类似

的 typeglob 赋值
*main::foo = *Custom::Module::foo;

这将使您从 main::foo() 调用的函数调用在 Custom::Module::foo().

中定义的代码

我已尝试完全按照您的描述重新创建文件。这是我的三个源文件

你说

In a script I am working on, I have something similar to the following:

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

When I try to call get_coll() I get an error about it

虽然你没有说你在哪里调用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;

然后你说

In the Custom::Module file, I start with

package Custom::Module;

and end with

1;

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

Custom/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' 吗?

如果您能指出我误解了您的描述的地方,请指出,因为我目前无法复制您的问题,因此无法帮助您

否则,我建议您尝试使用这三个文件来创建 Short, Self-Contained, Correct Example 您的问题。这将极大地帮助我们为您找到解决方案