Perl - Подпрограмма переопределена - PullRequest
25 голосов
/ 07 августа 2010

Я уже задавал этот вопрос раньше или искал и видел, как другие спрашивают - почему я получаю предупреждение " Подпрограмма mySub переопределена в строке ../lib/Common.pm x "?и вы всегда получаете ответ , который вы объявили дважды дважды в одном и том же коде .Я создал этот тестовый пакет:

ВЕСЬ ФАЙЛ ---------------

package MyCommonPkg;

use strict;

sub thisSubroutineIsNotDefinedAnywhereElse{
}

1;

ВСЕ ФАЙЛ ---------------

и я ИСПОЛЬЗУЮ этот пакет из сценария perl, который использует другие пакеты, которые также используют этот пакет, и я получаю предупреждение:

Подпрограмма ThisSubroutineIsNotDefinedAnywhereElse переопределенав ../lib/MyCommonPkg.pm строка 19.

Обещаю, что нигде больше не объявлял этот саб.Так это вызвано круговой ссылкой?Как я могу найти причину этого предупреждения и устранить его?

Ответы [ 9 ]

34 голосов
/ 07 августа 2010

Есть ли у вас цикл зависимости?Если 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.

Как правило, два пакета не должны зависеть друг от друга.Однако иногда цикл труднее найти, потому что он вызван третьим пакетом.

24 голосов
/ 11 августа 2012

Если у вас есть две подпрограммы с одинаковыми именами в разных пакетах, вы должны увидеть это предупреждение (когда предупреждения включены) как «Подпрограмма новая переопределена ....». Простая причина (которая очень близка к тому, что сказал Грант Маклин, но все же не совсем) заключается в том, что вы должны заставить ваши пакеты пропустить фазу компиляции и выполнить make, а затем require. Таким образом, менеджер пространства имен Perl не найдет таких конфликтующих символов с одинаковыми именами во время компиляции, и, если у ваших модулей нет ошибок, они также будут отлично работать после этого.

Просто убедитесь, что вы реализуете

требуется Модуль;

заявление вместо

использовать модуль;

Вы не должны видеть это предупреждение снова.

7 голосов
/ 07 августа 2010

Если вы работаете в системе с файловой системой без учета регистра (Windows и довольно часто OSX), и вы делаете use Common в одном файле и use common в другом, вы можете вызвать такие проблемы.

4 голосов
/ 21 января 2013

Это звучит как проблема, вызванная циклическими зависимостями.Вот как это отследить.Если ваш класс задач выглядит следующим образом:

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

Теперь, когда у вас есть трассировка стека, вы можете увидеть, где находится цикл.Быстрое и грязное решение заключается в использовании Class :: Load в Dinosaurs.pm.

Для более подробного объяснения попробуйте мой пост в блоге .

2 голосов
/ 27 февраля 2011

Вы случайно не запускаете это как cgi-скрипт на веб-сервере?

Я считаю, что мне нужно перезапустить веб-сервер, чтобы обойти это предупреждение.

1 голос
/ 27 октября 2013

Взгляните на программу 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. Это переменные $name и $dir внутри пакета File/Find.pm в пространстве имен File::Find.

Чтобы вам было проще, пакеты могут экспортировать свои переменные и подпрограммы в ваше пространство имен 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 автоматически, ничего не сообщая, импортирует подпрограммы copy и move в пространство имен 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 определяет четыре подпрограммы: thisSubroutineIsNotDefinedAnywhereElse, foo, bar и barfoo. Чтобы использовать любую из этих подпрограмм.

Вам нужно сделать это:

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

Не весело.

  • Используйте другое имя для вашей подпрограммы. Должно быть задокументировано, что эта подпрограмма определена в MyCommonPkg, и если вы хотите использовать MyCommonPkg, вы не должны использовать имена подпрограмм, которые экспортируются.

  • Наконец, если MyCommonPkg является довольно новым и не используется в десятках программ, используйте @EXPORT_OK вместо @EXPORT и убедитесь, что все программы, использующие MyCommonPkg, изменены на экспортируйте нужные им подпрограммы:

Вот так:

use MyCommonPkg qw(foo bar);

В этом случае экспортируются только подпрограммы foo и bar. Подпрограммы thisSubroutineIsNotDefinedAnywhereElse и barfoo не экспортируются в вашу среду.

0 голосов
/ 22 августа 2017

У меня была такая же проблема; Это произошло потому, что программа использовала модуль, а подпрограмма присутствовала как в программе, так и в модуле perl;

0 голосов
/ 02 мая 2012

Убедитесь, что вы не забыли эту строку в конце вашего модуля:

1;

Я знаю, что она была включена в несколько примеров здесь, но я упоминаюэто потому, что это легко упустить, и в моем случае это оказалось единственной причиной ошибок!

0 голосов
/ 07 августа 2010

Я пытался использовать «пакет Common.pm» в качестве имени пакета.Компилятор дал мне ошибки.Очень мило с этим, а?Какую версию Perl вы используете?Я пробовал это на 5.10.0 и 5.12.1.

Даже если вы можете скомпилировать, рекомендуется удалить файл .pm.Например;

Файл: some_package.pm;

package some_package;
use strict;

sub yadayadayada { ... }

1;
...