2010-08-06 2 views
23

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

весь файл ---------------

package MyCommonPkg; 

use strict; 

sub thisSubroutineIsNotDefinedAnywhereElse{ 
} 

1; 

весь файл -------------- -

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

SUBROUTINE ThisSubroutineIsNotDefinedAnywhereElse переопределен в ../lib/MyCommonPkg.pm линии 19.

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

+5

Действительно ли вы объявляете 'пакет Common.pm'? Это похоже на ошибку. – mob

+0

У вас есть два пакета с тем же именем? Это может вызвать столкновение пространства имен. Всегда указывайте свои пакеты для файла, в котором они находятся (заменяя '/' '::' и зачищая '.pm'). Это также может произойти, если у вас есть * no * namespace, что на самом деле означает, что вы находитесь в 'main'. – Ether

+0

нет - я не объявлял его Common.pm. Я просто переименовал вещи, чтобы получить пример псевдокода и опечатать. Я отредактирую. – user210757

ответ

7

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

+0

искали вхождения этого и не могли найти. очень хорошо знать, хотя - спасибо! – user210757

0

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

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

Файл: some_package.pm;

package some_package; 
use strict; 

sub yadayadayada { ... } 

1; 
+0

5.10.1 MS-win32-x86-mulithread – user210757

31

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

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

+2

Я думаю, что это моя проблема - как это исправить? это не круговая ссылка - я бы увидел круговую ссылку, поскольку PackageA «использует PackageB»; и PackageB имеет «использовать PackageA»; Скорее у меня есть сценарий «main.pl», который использует PackageA и использует PackageB, а PackageA также использует PackageB. Не должно быть ничего плохого в этом? – user210757

+0

Правильно, в этом не должно быть ничего плохого. –

2

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

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

+1

нет, просто работает из командной строки – user210757

0

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

1;

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

19

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

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

требуют модуля;

заявление, а не

использование модуля;

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

+0

спасибо, это решило мою проблему – Thariama

+0

Спасибо. Это была весьма полезная информация –

4

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

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 

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

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

1

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

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

Смежные вопросы