Perl - 重新定义子例程

发布于 2024-09-14 00:00:48 字数 538 浏览 8 评论 0原文

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

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

package MyCommonPkg;

use strict;

sub thisSubroutineIsNotDefinedAnywhereElse{
}

1;

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

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

Subroutine ThisSubroutineIsNotDefinedAnywhereElse redefine at ../lib/MyCommonPkg.pm line 19.

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

I have asked this question before or searched and seen others ask - why am I getting the warning "Subroutine mySub redefined at ../lib/Common.pm line x"? and you always get the answer you declared the sub twice in the same code. I created this test package:

ENTIRE FILE ---------------

package MyCommonPkg;

use strict;

sub thisSubroutineIsNotDefinedAnywhereElse{
}

1;

ENTIRE FILE ---------------

and I USE this package from a perl script, which uses other packages, that use this package also, and I get the warning:

Subroutine ThisSubroutineIsNotDefinedAnywhereElse redefined at ../lib/MyCommonPkg.pm line 19.

I promise I did not declare this sub anywhere else. So is this caused by a circular reference? How can I go about tracking the cause of this warning down and fixing?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

我偏爱纯白色 2024-09-21 00:00:48

你有依赖循环吗?如果 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 中的子例程被重新定义的消息。

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

Do you have a dependency loop? If Perl starts compiling your script and encounters a line like this:

use PackageA;

Perl pauses the compilation of your script; locates PackageA.pm and starts compiling it. If it encounters a line like this:

use PackageB;

Perl pauses the compilation of PackageA; locates PackageB.pm and starts compiling it. Normally, that would complete successfully, and Perl would go back to complete compiling PackageA and when that completes successfully it would go back to compiling your script and when that completes successfully it would start to execute the compiled opcodes.

However, if PackageB.pm contains this line:

use PackageA;

You might expect it would do nothing since Perl has already processed PackageA.pm but the problem is that it hasn't finished yet. So Perl will pause the compilation of PackageB and start compiling PackageA.pm again from the beginning. That could trigger the message you're seeing about subroutines in PackageA being redefined.

As a general rule, two packages should not both depend on each other. Sometimes however the loop is harder to locate because it is caused by a third package.

等待我真够勒 2024-09-21 00:00:48

当不同包中有两个同名的子例程时,您应该看到此警告(当启用警告时)为“子例程新重新定义......”。
简单的原因(这与 Grant McLean 所说的非常接近,但仍然不完全)是你必须让你的包跳过编译阶段并 make then require。这样,Perl 命名空间管理器在编译时就不会发现任何此类具有相同名称的冲突符号,并且如果您的模块没有任何错误,它们之后也会正常工作。

只需确保您实现

require 模块即可;

声明而不是

使用Module;

您不应再看到此警告。

When you have two subroutines with the same name in different packages, you ought to see this warning (when warnings are enabled) as "Subroutine new redefined....".
The simple reason (which is very close to what Grant McLean said, but still not exactly) is you must get your packages skip the compiling phase and make then require. This way, the Perl namespace manager will not find any such conflicting symbols with same name at compile time, and if you modules do not have any errors, they will work just fine afterwards also.

Just make sure you implement

require Module;

statement rather than

use Module;

You should not see this warning again.

笑红尘 2024-09-21 00:00:48

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

If you're on a system with a case-insensitive filesystem (Windows, and quite often OSX), and you do use Common in one file and use common in another, you can cause problems like this.

千笙结 2024-09-21 00:00:48

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

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

如需更详细的解释,请尝试我的博客文章

This sounds like a problem caused by circular dependencies. Here is how to track it down. If your problem class looks like this:

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

Then change your example to look like this:

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

Now compile your code with Carp::Always like this:

⚡ 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

Now that you have a stacktrace you can see where the loop is. The quick and dirty solution is to use Class::Load in Dinosaurs.pm.

For a more detailed explanation try my blog post.

ヤ经典坏疍 2024-09-21 00:00:48

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

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

Are you by any chance running this as a cgi-script on a web-server?

I find I need to restart the webserver to get around this warning.

舞袖。长 2024-09-21 00:00:48

看一下程序 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::FindFile/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);

包 File::Copy; 定义了一个命名空间。 require Exporter;@ISA = qw(Exporter) 允许包将子例程和变量导出到 main 命名空间中。 @EXPORT 会自动将 copymove 子例程导入到 main 命名空间中,而无需告诉您任何信息。 strong>无论您是否想要它们!

最后一点非常重要。现在使用 @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,则不应使用导出的子例程名称。

  • 最后,如果 MyCommonPkg 相当新,并且未在数十个程序中使用,请使用 @EXPORT_OK 而不是 @EXPORT,并确保所有使用 MyCommonPkg 的程序都被修改为导出它们想要的子例程:

像这样:

use MyCommonPkg qw(foo bar);

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

Take a look at the program package MyCommonPkg.pm and see what it says. Does it have something like this?

package MyCommonPkg;

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

The syntax may be a bit different. The main things you should see are the package statement, that it's using Exporter and that the @EXPORT array has your subroutine's name in it.

What is going on is a namespace clash. Your package is defining the same subroutine you're defining.

In order to prevent this from happening, Perl uses namespaces. By default, your namespace is main. However, packages are suppose to define their own separate namesakes using the package command.

The full namespace of a subroutine or variable is the namespace followed by a double colon, followed by the subroutine or variable name. For example, of you look at File::Find, you will see references to the variables $File::Find::name and $File::Find::dir. These are the variables $name and $dir inside the File/Find.pm package under the File::Find namespace.

In order to make things easier for you, packages can export their variables and subroutines into your main namespace. For example, if I use File::Copy, O can do this:

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

Instead of:

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

If you look at File/Copy.pm, you will see the following:

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

The package File::Copy; defines a namespace. The require Exporter; and the @ISA = qw(Exporter) allows the package to export subroutines and variables into the main namespace. The @EXPORT automatically, without it telling you anything, imports the copy and move subroutines into the main namespace whether you want them or not!

That last bit is very important. It is now considered bad manners to use @EXPORT. Instead, you should use @EXPORT_OK which requires you to list the subroutines you want to use. More modern packages like Scalar::Util do this.

So several things. First, does your MyCommonPkg have a package MyCommonPkg; statement. If not, it should. This keeps the packages subroutines and variables from affecting your program in nasty ways. Then, you can use @EXPORT or @EXPORT_OK.

If MyCommonPkg does have a package statement, does it use @EXPORT? If so, you have several ways you can avoid this issue:

  • Ignore the warning. It's just a warning. Since you know you're redefining the subroutine, and you want to use your definition of the subroutine, ignore it.

You can do this to turn off the warning as you redefine the subroutine:

use MyCommonPkg;

no warnings qw(redefine);
sub thisSubroutineIsNotDefinedAnywhereElse {
   ...
}
use warnings qw(redefine);
  • Use require MyCommonPkg; instead of use MyCommonPkg;. This will prevent the importing of any subroutines or variables into your namespace including ones you wanted to use. Let's say MyCommonPkg defines four subroutines: thisSubroutineIsNotDefinedAnywhereElse, foo, bar, and barfoo. To use any of these subroutines.

You need to do this:

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

Not fun.

  • Use another name for your subroutine. It should have been documented that this subroutine is defined in MyCommonPkg, and if you want to use MyCommonPkg, you shouldn't use subroutine names that are exported.

  • Finally, if MyCommonPkg is fairly new, and isn't used in dozens of programs, use @EXPORT_OK instead of @EXPORT, and make sure all the programs that use MyCommonPkg are modified to export the subroutines they want:

Like this:

use MyCommonPkg qw(foo bar);

In this case, only subroutines foo and bar are exported. The subroutines thisSubroutineIsNotDefinedAnywhereElse and barfoo are not exported into your environment.

听不够的曲调 2024-09-21 00:00:48

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

即使您可以编译,删除 .pm 文件也是一个好习惯。例如;

文件:some_package.pm;

package some_package;
use strict;

sub yadayadayada { ... }

1;

I tried to use "package Common.pm" as a package name. The compiler gave me errors. Very kind of it eh? What version of Perl are you using? I tried it on 5.10.0 and 5.12.1.

Even if you can compile it is good practice to remove the .pm file. For Example;

File: some_package.pm;

package some_package;
use strict;

sub yadayadayada { ... }

1;
失退 2024-09-21 00:00:48

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

1;

我知道它已包含在此处的一些示例中,但我提到它是因为它很容易被忽视,并且就我而言,这是错误的唯一原因!

Make sure you didn't forget this line at the end of your module:

1;

I know it's been included in a few of the examples here, but I mention it because it is easy to overlook, and in my case it turned out to be the sole cause of the errors!

丑丑阿 2024-09-21 00:00:48

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

I had the same problem; It was because the program used a module and the subroutine was present both in the program and in the perl module;

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文