【问题标题】:Perl - Subroutine redefinedPerl - 重新定义子程序
【发布时间】:2011-03-26 14:09:14
【问题描述】:

我之前曾问过这个问题,或者搜索并看到其他人问过 - 为什么我会收到警告“Subroutine mySub redefined at ../lib/Common.pm line x”?并且您总是会得到答案您在同一代码中两次声明了 sub。我创建了这个测试包:

整个文件---------------

package MyCommonPkg;

use strict;

sub thisSubroutineIsNotDefinedAnywhereElse{
}

1;

整个文件---------------

我使用 perl 脚本中的这个包,它使用其他包,也使用这个包,我收到警告:

子例程 ThisSubroutineIsNotDefinedAnywhereElse 在 ../lib/MyCommonPkg.pm 第 19 行重新定义。

我保证我没有在其他任何地方声明这个子。那么这是由循环引用引起的吗?我该如何着手跟踪并修复此警告的原因?

【问题讨论】:

  • 你真的声明package Common.pm吗?这似乎是一个错误。
  • 你碰巧有两个同名的包吗?这可能会导致命名空间冲突。始终为其所在的文件命名您的包(将/ 替换为::,并剥离.pm)。如果您有 no 命名空间,这也可能发生,这实际上意味着您在 main
  • 不 - 我没有声明它 Common.pm。我只是重命名了一些东西以获取伪代码示例并输入错误。我会编辑。

标签: perl subroutine


【解决方案1】:

如果您使用的系统具有不区分大小写的文件系统(Windows,通常是 OSX),并且您在一个文件中使用 use Common 而在另一个文件中使用 use common,则可能会导致此类问题。

【讨论】:

  • 搜索了这种情况,但没有找到。很高兴知道 - 谢谢!
【解决方案2】:

我尝试使用“package Common.pm”作为包名。编译器给了我错误。很亲切吧?你用的是什么版本的 Perl?我在 5.10.0 和 5.12.1 上试过。

即使您可以编译,最好还是删除 .pm 文件。例如;

文件:some_package.pm;

package some_package;
use strict;

sub yadayadayada { ... }

1;

【讨论】:

    【解决方案3】:

    你有依赖循环吗?如果 Perl 开始编译你的脚本并遇到这样的一行:

    use PackageA;
    

    Perl 暂停脚本的编译;找到 PackageA.pm 并开始编译它。如果遇到这样的一行:

    use PackageB;
    

    Perl 暂停 PackageA 的编译;找到 PackageB.pm 并开始编译它。通常,这会成功完成,Perl 会返回完成编译 PackageA,当它成功完成时,它会返回编译你的脚本,当它成功完成时,它会开始执行编译的操作码。

    然而,如果 PackageB.pm 包含这一行:

    use PackageA;
    

    由于 Perl 已经处理了 PackageA.pm,您可能认为它什么也不会做,但问题是它还没有完成。所以 Perl 会暂停 PackageB 的编译,重新从头开始编译 PackageA.pm。这可能会触发您看到的有关重新定义 PackageA 中的子例程的消息。

    作为一般规则,两个包不应都相互依赖。然而,有时循环更难定位,因为它是由第三个包引起的。

    【讨论】:

    • 我认为这是我的问题 - 那么如何解决?它不是循环引用 - 我会看到循环引用,因为 PackageA 有“使用 PackageB;”并且 PackageB 具有“使用 PackageA;”相反,我有一个脚本“main.pl”,它使用 PackageA 并使用 PackageB,而 PackageA 也使用 PackageB。应该不会有什么问题吧?
    【解决方案4】:

    您是否有机会在网络服务器上将其作为 cgi 脚本运行?

    我发现我需要重新启动网络服务器才能绕过此警告。

    【讨论】:

      【解决方案5】:

      确保您没有忘记模块末尾的这一行:

      1;

      我知道它已包含在此处的一些示例中,但我之所以提到它是因为它很容易被忽视,而在我的情况下,它是导致错误的唯一原因!

      【讨论】:

        【解决方案6】:

        当你在不同的包中有两个同名的子程序时,你应该看到这个警告(当警告被启用时)为“Subroutine new redefined....”。 一个简单的原因(这与格兰特麦克莱恩所说的非常接近,但仍然不完全是)是你必须让你的包跳过编译阶段然后 make 然后 require。这样,Perl 命名空间管理器将不会在编译时找到任何此类具有相同名称的冲突符号,并且如果您的模块没有任何错误,它们之后也可以正常工作。

        只要确保你实现了

        需要模块;

        声明而不是

        使用模块;

        您应该不会再看到此警告。

        【讨论】:

        • 在不同的包中可以有同名的潜艇。 Perl 不会对此发出警告 - 这有点像包的意义:)
        【解决方案7】:

        这听起来像是循环依赖引起的问题。以下是如何追踪它。如果您的问题类如下所示:

        package AlientPlanet;
        use Dinosaurs;
        sub has_dinosaurs {...}
        1;
        

        然后将您的示例更改为如下所示:

        package AlienPlanet;
        sub has_dinosaurs {...}     # <-- swap
        use Dinosaurs;              # <-- swap
        1;
        

        现在使用Carp::Always 编译您的代码,如下所示:

        ⚡ perl -MCarp::Always -c lib/AlienPlanet.pm                                                                                                            
        Subroutine has_dinosaurs redefined at lib/AlienPlanet.pm line 4.
            require AlienPlanet.pm called at lib/Dinosaurs.pm line 4
            Dinosaurs::BEGIN() called at lib/AlienPlanet.pm line 4
            eval {...} called at lib/AlienPlanet.pm line 4
            require Dinosaurs.pm called at lib/AlienPlanet.pm line 5
            AlienPlanet::BEGIN() called at lib/AlienPlanet.pm line 4
            eval {...} called at lib/AlienPlanet.pm line 4
        lib/AlienPlanet.pm syntax OK
        

        现在您有了堆栈跟踪,您可以看到循环在哪里。快速而肮脏的解决方案是在 Dinosaurs.pm 中使用Class::Load

        如需更详细的解释,请尝试我的blog post

        【讨论】:

          【解决方案8】:

          看看程序package MyCommonPkg.pm,看看它说了什么。有这样的吗?

          package MyCommonPkg;
          
          use Exporter qw(import);   #  Might be "require" and not "use"
          our @EXPORT = qw(thisSubroutineIsNotDefinedAnywhereElse);
          

          语法可能有点不同。您应该看到的主要内容是 package 语句,它正在使用 Exporter 并且 @EXPORT 数组中包含您的子例程的名称。

          正在发生的是命名空间冲突。您的包正在定义您正在定义的相同子例程。

          为了防止这种情况发生,Perl 使用了命名空间。默认情况下,您的命名空间是main。但是,包应该使用package 命令定义自己的独立同名。

          子程序或变量的完整命名空间是命名空间后跟一个双冒号,然后是子程序或变量名。例如,如果您查看File::Find,您将看到对变量$File::Find::name$File::Find::dir 的引用。这些是File::Find 命名空间下File/Find.pm 包内的变量$name$dir

          为了方便您,包可以导出它们的变量和子例程到您的 main 命名空间中。例如,如果我使用File::Copy,O 可以这样做:

          ...
          use File::Copy
          ...
          copy ($file, $to_dir);
          

          代替:

          ...
          use File::Copy
          ...
          File::Copy::copy ($file, $to_dir);
          

          如果您查看File/Copy.pm,您将看到以下内容:

          package File::Copy;
          ...
          our(@ISA, @EXPORT, @EXPORT_OK, $VERSION, $Too_Big, $Syscopy_is_copy);
          ...
          require Exporter;
          @ISA = qw(Exporter);
          @EXPORT = qw(copy move);
          

          package File::Copy; 定义了一个命名空间。 require Exporter;@ISA = qw(Exporter) 允许包将子例程和变量导出到 main 命名空间。 @EXPORT 会自动将copymove 子例程导入到main 命名空间不管你是否想要它们!

          最后一点非常重要。现在使用@EXPORT 被认为是不礼貌。相反,您应该使用@EXPORT_OK,它要求您列出要使用的子例程。像Scalar::Util 这样的更现代的软件包就是这样做的。

          有几件事。首先,您的MyCommonPkg 是否有package MyCommonPkg; 声明。如果没有,它应该。这可以防止包子例程和变量以讨厌的方式影响您的程序。然后,您可以使用@EXPORT@EXPORT_OK

          如果MyCommonPkg 确实有package 语句,它是否使用@EXPORT?如果是这样,您有几种方法可以避免此问题:

          • 忽略警告。这只是一个警告。既然您知道自己正在重新定义子例程,并且想要使用您对子例程的定义,请忽略它。

          您可以在重新定义子例程时关闭警告:

          use MyCommonPkg;
          
          no warnings qw(redefine);
          sub thisSubroutineIsNotDefinedAnywhereElse {
             ...
          }
          use warnings qw(redefine);
          
          • 使用require MyCommonPkg; 而不是use MyCommonPkg;。这将防止将任何子例程或变量导入您的命名空间,包括您想要使用的那些。假设MyCommonPkg 定义了四个子例程:thisSubroutineIsNotDefinedAnywhereElsefoobarbarfoo。使用任何这些子例程。

          你需要这样做:

          my $answer = MyCommonPkg::foo( $input );
          

          不好玩。

          • 为您的子例程使用另一个名称。应该已经记录了这个子程序是在MyCommonPkg中定义的,如果你想使用MyCommonPkg,你不应该使用导出的子程序名称。

          • 1234563导出他们想要的子程序:

          像这样:

          use MyCommonPkg qw(foo bar);
          

          在这种情况下,仅导出子例程 foobar。子例程 thisSubroutineIsNotDefinedAnywhereElsebarfoo 不会导出到您的环境中。

          【讨论】:

            【解决方案9】:

            我遇到了同样的问题;这是因为程序使用了一个模块,而子程序同时存在于程序和perl模块中;

            【讨论】:

              猜你喜欢
              • 2011-07-03
              • 1970-01-01
              • 2015-05-02
              • 2013-08-21
              • 2015-10-22
              • 1970-01-01
              • 2013-08-13
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多