【发布时间】:2015-12-07 07:15:23
【问题描述】:
我遇到了 Perl 模块的命名空间问题。当我在常规脚本文件中use 它时,所有公共符号都按预期导入到(隐式)main:: 包中。但是,当我尝试在具有自己的包声明(即通常是另一个模块)的源文件中 use 时,奇怪的事情开始发生。
可以在 CPAN 上以 Ufal::MorphoDiTa 找到相关模块。它是一组与 C++ 库的绑定,使用 SWIG 自动生成。无需安装 lib 本身即可重现以下测试用例。
然后是一个没有包声明的常规脚本文件:
# script.pl
use Ufal::MorphoDiTa qw(:all);
use Data::Dumper;
# a closer look at symbols inside the main:: package
my %morph_in_main = %main::{ grep { /morph/i } keys %main:: };
print "main:: namespace:\n", Dumper \%morph_in_main;
# Morpho:: is exported by Ufal::MorphoDiTa
Morpho::load('foo');
正如预期的那样,Ufal::MorphoDiTa 中的符号被导入main:: 并调用Morpho::load 子例程(没有可见的输出,但这很好):
$ perl script.pl
main:: namespace:
$VAR1 = {
'Morpho::' => *{'Ufal::MorphoDiTa::Morpho::'},
'_<morphodita/morphodita_perl.cpp' => *{'::_<morphodita/morphodita_perl.cpp'},
'_</usr/local/Cellar/perl/5.22.0/lib/site_perl/5.22.0/darwin-thread-multi-2level/auto/Ufal/MorphoDiTa/MorphoDiTa.bundle' => *{'::_</usr/local/Cellar/perl/5.22.0/lib/site_perl/5.22.0/darwin-thread-multi-2level/auto/Ufal/MorphoDiTa/MorphoDiTa.bundle'}
};
现在让我们添加一个包声明:
# Qux.pm
package Qux;
use Ufal::MorphoDiTa qw(:all);
use Data::Dumper;
# a closer look at symbols inside the main:: package
my %morph_in_main = %main::{ grep { /morph/i } keys %main:: };
print "main:: namespace:\n", Dumper \%morph_in_main;
# a closer look at symbols inside the Qux:: package
my %morph_in_qux = %Qux::{ grep { /morph/i } keys %Qux:: };
print "Qux:: namespace:\n", Dumper \%morph_in_qux;
# Morpho:: is exported by Ufal::MorphoDiTa
Morpho::load('foo');
如下所示,在这种情况下,一些导入的符号最终出现在 main:: 包中,而一些则出现在声明的 Qux:: 包中(也许这是预期的行为?):
$ perl Qux.pm
main:: namespace:
$VAR1 = {
'_<morphodita/morphodita_perl.cpp' => *{'::_<morphodita/morphodita_perl.cpp'},
'Morpho::' => *{'::Morpho::'},
'_</usr/local/Cellar/perl/5.22.0/lib/site_perl/5.22.0/darwin-thread-multi-2level/auto/Ufal/MorphoDiTa/MorphoDiTa.bundle' => *{'::_</usr/local/Cellar/perl/5.22.0/lib/site_perl/5.22.0/darwin-thread-multi-2level/auto/Ufal/MorphoDiTa/MorphoDiTa.bundle'}
};
Qux:: namespace:
$VAR1 = {
'Morpho::' => *{'Ufal::MorphoDiTa::Morpho::'}
};
Undefined subroutine &Morpho::load called at Qux.pm line 11.
无论如何,正如输出的最后一行所示,Perl 突然找不到子例程了。请注意,我们真正做的只是在所有 use 语句之前添加包声明。
现在最重要的是——如果我们use Ufal::MorphoDiTa之前声明package Qux,一切都会重新开始工作:
# Qux.pm
use Ufal::MorphoDiTa qw(:all);
package Qux;
use Data::Dumper;
# etc.
使用perl Qux.pm 运行模块的输出与第一种情况相同,即找到子Morpho::load,尽管没有以main:: 命名空间为前缀它被加载到其中。将此与 Data::Dumper 这样的标准模块的行为进行对比——当 that 在包声明之前加载时,子 Dumper 在包 @987654346 中时必须被称为 main::Dumper @。
我会很感激任何关于这里发生的事情的指针......这并不是我无法解决它,而是这个问题困扰着我——我不确定这是否是 Perl 的一个怪癖,一个错误在 SWIG 方面(我没有足够的 Perl-Fu 来理解自动生成的绑定模块,它到处都有包声明),或者(另一种可能的选择)我自己的无知是否有错这里。感谢您的任何意见! :)
【问题讨论】:
标签: perl module namespaces package swig