为什么包A中的函数在递归调用时不会导入到包B中?

时间:2012-07-17 11:31:53

标签: perl recursion package

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

未定义的子程序& 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;

3 个答案:

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

  1. perl开始解析test.pl
  2. 它看到use module1;所以它加载module1.pm并开始解析它
  3. perluse module2;中看到module1.pm,因此它会加载module2.pm并开始解析
  4. 此时,module1中的功能尚不存在,因此无法导入
  5. 解析继续
  6. 鲍罗丁说的东西让我得到了最好的解决方案:“@ 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的另一个论点。