4

我正在尝试使用两个包并从一个到另一个调用函数,但是我遇到了这个错误:

未定义的子例程 &module2::method_1_2 在 module2.pm 第 20 行调用。

有没有办法从一个包调用函数到另一个包而不会出现此错误?

提前致谢。

夏比

执行错误:

./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();

模块1.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;

模块2.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;
4

3 回答 3

3

问题是您@EXPORT在它已经使用后分配给它。以下内容抄自迷你教程:导出模块的相互使用


[ 使用这种技术的需要是系统中设计缺陷的一个非常强烈的指标,但我认识到资源并不总是可用于修复设计缺陷。]

如果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;
于 2012-07-17T15:33:28.123 回答
3

问题是,首先要做的module1use module2。这意味着在仍在编译的module2同时读取并执行所有内容。module1

接下来发生的事情就是module2这样use module1。因为module1已经找到并放入%INCPerl 不会再次执行它,而只是module1->import获取导出的符号。

但当然module1实际上几乎没有开始编译,@module1::EXPORT甚至不存在,更不用说它的两个子例程了。这使得Exporterimport 什么都没有进入module2,因此在进行调用时,method_1_2()它对此一无所知。

解决此问题的最简洁方法是在编译之后(包括所有use语句和BEGIN块)但运行时之前进行导入。Perl 的INIT非常适合这种情况,我们可以通过将模块更改为下面的形式来使代码正常工作。我只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;
于 2012-07-17T13:36:48.527 回答
1

有趣的是,我不确定为什么method_1_2没有被导出到module2命名空间中,但是您可以通过显式引用包来解决这个问题:

模块1.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;

模块2.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块在解析后立即运行,因此代码在执行顺序上看起来像这样。

  1. perl开始解析test.pl
  2. 它看到use module1;所以它加载module1.pm并开始解析它
  3. perl看到所以它加载并use module2;开始解析它module1.pmmodule2.pm
  4. 此时,里面的函数module1还不存在,所以无法导入
  5. 解析继续

Borodin 说的一些话让我找到了最好的解决方案:“@module1::EXPORT 甚至不存在”。这里的问题是该@EXPORT变量不存在。这可以通过将它放在一个BEGIN块中来解决:

模块1.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;

模块2.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被编译module1的,所以它不知道原型存在)。这是另一个永远不要使用原型的论点。

于 2012-07-17T12:48:30.963 回答