我正在尝试使用两个软件包并将函数从一个调用到另一个,但我遇到了这个错误:
未定义的子程序& module2 :: method_1_2在module2.pm第20行调用。
有没有办法将函数从一个包调用到另一个包而不会出现此错误?
提前致谢。
哈维
exec错误:
./test.pl
method_1_1
method_2_1
method_2_2
Undefined subroutine &module2::method_1_2 called at module2.pm line 20.
示例代码(test.pl):
#!/usr/bin/perl
use strict;
use module1;
use module2;
method_1_1();
method_2_2();
module1.pm
package module1;
use strict;
use module2;
require Exporter;
use vars qw(@ISA @EXPORT);
@ISA = qw(Exporter);
@EXPORT = qw( method_1_1 method_1_2 );
sub method_1_1
{
print "method_1_1\n";
method_2_1();
}
sub method_1_2
{
print "method_1_2\n";
}
1;
module2.pm:
package module2;
use strict;
use module1;
require Exporter;
use vars qw(@ISA @EXPORT);
@ISA = qw(Exporter);
@EXPORT = qw( method_2_1 method_2_2 );
sub method_2_1
{
print "method_2_1\n";
}
sub method_2_2
{
print "method_2_2\n";
method_1_2();
}
1;
答案 0 :(得分:3)
问题是module1
做的第一件事就是use module2
。这意味着在module2
仍在编译时会读取并执行所有module1
。
接下来要做的是module2
执行use module1
。因为module1
已找到并放入%INC
Perl不再执行它,只需module1->import
来获取导出的符号。
但是当然module1
实际上几乎没有开始编译,@module1::EXPORT
甚至不存在,更不用说它的两个子程序了。这使得Exporter
根本无法导入module2
,因此在进行调用method_1_2()
时,它对此一无所知。
解决此问题的最简单方法是在编译之后执行导入(包括所有use
语句和BEGIN
块),但之前 >运行时。 Perl的INIT
block是理想的,我们可以通过将模块更改为下面的表单来获得代码。我在这里只显示module2
,因为调用模式意味着这就是解决这个特定问题所需的全部内容,但是一般情况需要对所有合作模块进行等效更改。
package module2;
use strict;
use warnings;
use module1;
INIT { module1->import }
use base 'Exporter';
our @EXPORT = qw( method_2_1 method_2_2 );
sub method_2_1 {
print "method_2_1\n";
}
sub method_2_2 {
print "method_2_2\n";
method_1_2();
}
1;
答案 1 :(得分:2)
问题是您已经使用后分配给@EXPORT
。以下内容从Mini-Tutorial: Mutual Use of Exporting Modules
[需要使用这种技术是系统设计缺陷的一个非常有力的指标,但我认识到资源并不总是可用于修复设计缺陷。 ]
如果ModA使用ModB,ModB使用ModA,ModA或ModB从另一个导入符号,则需要注意代码执行顺序。我发现避免出现问题的最好方法是在加载任何其他模块之前设置Exporter。
# ModA.pm
package ModA;
use strict;
use warnings;
use Exporter qw( import );
BEGIN { our @EXPORT_OK = qw( ... ); }
use This;
use ModB;
use That;
...
1;
# ModB.pm
package ModB;
use strict;
use warnings;
use Exporter qw( import );
BEGIN { our @EXPORT_OK = qw( ... ); }
use This;
use ModA;
use That;
...
1;
答案 2 :(得分:1)
有趣的是,我不确定为什么method_1_2
没有被导出到module2
命名空间,但你可以通过显式引用包来解决这个问题:
module1.pm
package module1;
use strict;
use warnings;
use module2 (); #don't import methods
use base 'Exporter';
our @EXPORT = qw( method_1_1 method_1_2 );
sub method_1_1
{
print "method_1_1\n";
module2::method_2_1();
}
sub method_1_2
{
print "method_1_2\n";
}
1;
module2.pm
package module2;
use strict;
use warnings;
use module1 (); #don't import methods
use base 'Exporter';
our @EXPORT = qw( method_2_1 method_2_2 );
sub method_2_1
{
print "method_2_1\n";
}
sub method_2_2
{
print "method_2_2\n";
module1::method_1_2();
}
1;
好吧,我想我看到了发生了什么事,但是带着一点点盐。 use
函数实际上是BEGIN
块,BEGIN
块在解析后立即运行,因此代码在执行顺序中看起来像这样。
perl
开始解析test.pl
use module1;
所以它加载module1.pm
并开始解析它perl
在use module2;
中看到module1.pm
,因此它会加载module2.pm
并开始解析module1
中的功能尚不存在,因此无法导入鲍罗丁说的东西让我得到了最好的解决方案:“@ module1 :: EXPORT甚至不存在”。这里的问题是@EXPORT
变量不存在。这可以通过将其放在BEGIN
块中来修复:
module1.pm
package module1;
use strict;
use warnings;
use base 'Exporter';
BEGIN {
our @EXPORT = qw( method_1_1 method_1_2 );
}
use module2;
sub method_1_1
{
print "method_1_1\n";
module2::method_2_1();
}
sub method_1_2
{
print "method_1_2\n";
}
1;
module2.pm
package module2;
use strict;
use warnings;
use base 'Exporter';
BEGIN {
our @EXPORT = qw( method_2_1 method_2_2 );
}
use module1;
sub method_2_1
{
print "method_2_1\n";
}
sub method_2_2
{
print "method_2_2\n";
method_1_2();
}
1;
重要提示:我不相信module1
module2
中的prototypes会在任何这些情况下受到尊重(我不知道自module1
编译之前它们是如何编译的{{1}} {1}},所以它无法知道原型存在)。这是never use prototypes的另一个论点。