Подтвердить что ты не робот

Perl - переопределенная подпрограмма

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

ПОЛНЫЙ ФАЙЛ ---------------

package MyCommonPkg;

use strict;

sub thisSubroutineIsNotDefinedAnywhereElse{
}

1;

ПОЛНЫЙ ФАЙЛ ---------------

и я использую этот пакет из perl script, который использует другие пакеты, которые также используют этот пакет, и я получаю предупреждение:

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

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

4b9b3361

Ответ 1

У вас есть цикл зависимостей? Если Perl начинает компилировать ваш script и встречает такую ​​строку:

use PackageA;

Perl приостанавливает компиляцию вашего script; находит PackageA.pm и начинает компилировать его. Если он встречает такую ​​строку:

use PackageB;

Perl приостанавливает компиляцию PackageA; находит PackageB.pm и начинает компилировать его. Как правило, это будет успешно завершено, и Perl вернется к полной компиляции пакета PackageA, и когда это будет завершено успешно, оно вернется к компиляции вашего script, и когда это будет успешно завершено, он начнет выполнять скомпилированные коды операций.

Однако, если PackageB.pm содержит эту строку:

use PackageA;

Вы можете ожидать, что это ничего не сделало, поскольку Perl уже обработал PackageA.pm, но проблема в том, что он еще не закончен. Поэтому Perl приостанавливает компиляцию PackageB и снова начинает компилировать PackageA.pm с самого начала. Это может вызвать сообщение, которое вы видите о подпрограммах в переопределении PackageA.

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

Ответ 2

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

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

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

, а не

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

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

Ответ 3

Вы не можете return с главной линии. Это должно быть только 1. Например:

#...
sub thisSubroutineIsNotDefinedAnywhereElse{
}

1;

Вы можете иногда слышать людей о том, как модули должны "возвращать 1", но так вы это делаете. Не return 1;.

Ответ 4

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

Ответ 5

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

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.

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

Ответ 6

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

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

Ответ 7

Посмотрите на программу 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.

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

Этот последний бит очень важен. В настоящее время считается плохим манером использовать @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;. Это предотвратит импорт любых подпрограмм или переменных в ваше пространство имен, включая те, которые вы хотели использовать. Пусть say 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 не экспортируются в вашу среду.

Ответ 8

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

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

Файл: some_package.pm;

package some_package;
use strict;

sub yadayadayada { ... }

1;

Ответ 9

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

1;

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

Ответ 10

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