【问题标题】:Perl - Package/Module IssuesPerl - 包/模块问题
【发布时间】:2010-06-04 20:59:25
【问题描述】:

从我读过的关于使用 Perl 模块的所有内容来看,基本用法是:

  • 带有.pm 扩展名的模块文件,其中包含package <name> 语句,其中<name> 是不带扩展名的模块的文件名。
  • 使用模块的代码文件包含语句use <name>;

我正在编写的应用程序有一个主要的代码脚本,它使用了大约 5 个模块。我忘记在模块中包含package <name> 语句,但我的代码在use <name> 语句中仍然运行良好。我开始收到其中一个模块的Undefined subroutine 错误,因此我将包语句添加到每个模块中。现在这些模块的其余部分停止工作。什么给了?

例子:

mainapp.pl

#!/usr/bin/perl
use UtyDate;
my $rowDate = CurrentDate("YYYYMMDD");

UtyDate.pm

#!/usr/bin/perl
package UtyDate;
sub CurrentDate
{
    #logic
}
return 1;

当我运行上面的代码时,我得到了错误Undefined subroutine &main::CurrentDate called at...。但是,如果我从 UtyDate.pm 中删除 package UtyDate; 行,则不会出现错误。这种情况存在于我的几个但不是所有模块中。

显然还有很多我没有显示的代码,但我很困惑我没有显示的任何代码会如何影响我在此处显示的包/使用构造。

【问题讨论】:

    标签: perl perl-module


    【解决方案1】:

    当您使用模块时,模块中的代码在编译时运行。然后在模块的包名上调用 import。所以,use Foo;BEGIN { require Foo; Foo->import; } 是一样的

    您的代码在没有package 声明的情况下工作,因为所有代码都在包main 下执行,主应用程序代码使用该包。

    当您添加 package 声明时,它停止工作,因为您定义的子例程不再在 main 中定义,而是在 UtyDate 中定义。

    您可以使用完全限定名称UtyDate::CurrentDate(); 访问子例程,也可以在use 模块时将子例程导入当前名称空间。

    UtyDate.pm

    package UtyDate;
    use strict;
    use warnings; 
    
    use Exporter 'import';
    
    # Export these symbols by default.  Should be empty!    
    our @EXPORT = ();
    
    # List of symbols to export.  Put whatever you want available here.
    our @EXPORT_OK = qw( CurrentDate  AnotherSub ThisOneToo );
    
    sub CurrentDate {
        return 'blah';
    }
    
    sub AnotherSub { return 'foo'; }
    

    主程序:

    #!/usr/bin/perl
    use strict;
    use warnings; 
    
    use UtyDate 'CurrentDate';
    
    # CurrentDate is imported and usable.    
    print CurrentDate(), " CurrentDate worked\n";
    
    # AnotherSub is not
    eval {  AnotherSub() } or print "AnotherSub didn't work: $@\n";
    
    # But you can still access it by its fully qualified name
    print UtyDate::AnotherSub(), " UtyDate::AnotherSub works though\n";
    

    有关详细信息,请参阅 Exporter 文档。

    【讨论】:

    • OP 应该首先阅读 perlmod (search.cpan.org/perldoc/perlmod) 作为了解 Exporter 中发生的事情的先决条件。
    • 很好的解释,谢谢。我在一些我看到的例子中看到了 Exporter,但不是全部,所以我认为它是无关的。我去看看 doc too mobrule,谢谢。
    【解决方案2】:

    您缺少导出器 perl 标头代码。您需要在 pm 文件顶部的 package 语句下方添加如下内容:

    package UtyDate;
    BEGIN {
      use Exporter ();
      use vars qw($VERSION @ISA @EXPORT);
      $VERSION = "1.0.0";
      @ISA = qw(Exporter);
      @EXPORT = qw( &CurrentDate );
    }
    

    查看此链接:http://perldoc.perl.org/Exporter.html#DESCRIPTION

    【讨论】:

    【解决方案3】:

    除了 Gray 的建议,您也可以这样做:

    use UtyDate;
    UtyDate::CurrentDate(...);
    

    【讨论】:

      【解决方案4】:

      除了使用导出器,正如 Gray 指出的那样,你可以(丑陋,但有效)也可以调用带有模块名称的函数 ..

      您的函数/程序不起作用,因为它们现在位于不同的命名空间(由模块名称定义)

      use UtyDate;
      
      UtyDate::CurrentDate(  )
      

      【讨论】:

      • 那不丑;这是调用不是以 OO 风格编写的函数的标准方式。
      • 命名空间由package 调用定义,而不是模块的名称。包名和模块名相同只是一种约定(虽然很好)。
      • @Ether:我担心,成为标准并不等于“不丑”。此外,与 Gray 的“解决方案”相比,我的意思是“丑陋”,这需要对已经编写的代码进行更少的更改(“很大的变化”是我认为“丑陋”的地方:变化会导致错误。YMMV
      猜你喜欢
      • 2019-02-27
      • 1970-01-01
      • 1970-01-01
      • 2011-12-31
      • 2013-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多