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

时间:2015-05-22 18:41:44

标签: perl module namespaces

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

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的陈述正在改变"活跃的"因此,当处理get_coll()时(因为它在调用时被处理),它被分配给该命名空间而不是main。对于常规的perl模块来说,这似乎不是一个问题,但是从我看过的那些模块中,我还没有发现任何会导致名称空间被“恢复”的东西。 ;模块加载后返回main。任何有助于更好地理解命名空间使用或修复模块以避免此问题的帮助都将非常感激。

旁注:对于我来说,仅仅需要"这不是一个很大的问题。模块,但这对我来说是意想不到的行为所以我大多只是想更好地理解为什么发生了什么事。

2 个答案:

答案 0 :(得分:1)

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

你说

  

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

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

如果你能指出我误解你的描述的地方那么请你这样做,因为我目前无法复制你的问题所以无法帮助你

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

答案 1 :(得分:0)

你错误地认为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,那么这些都不会有任何不同。

现在,在没有Custom::Module::bar()的情况下始终输入main::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的幕后完成。具体来说,从包use Custom::Module调用mainExporter进行类型地理分配,例如

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

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