Зачем нужны строгие правила и предупреждения?

104

Мне кажется, что многие вопросы в теге Perl можно было бы решить, если бы люди использовали:

use strict;
use warnings;

Я думаю, что некоторые люди считают это сродни тренировочным колесам или ненужным усложнениям, что явно неверно, поскольку их используют даже очень опытные программисты Perl.

Кажется, что большинство людей, разбирающихся в Perl, всегда используют эти две прагмы, тогда как те, кто извлек бы наибольшую пользу от их использования, редко. Итак, я подумал, что было бы неплохо иметь вопрос, на который можно было бы ссылаться при поощрении людей к use strictи warnings.

Итак, зачем разработчику Perl use strictи warnings?

TLP
источник
14
Я всегда задаюсь вопросом, почему они просто не делают это по умолчанию, а разработчику действительно нужно активно ослаблять материал, где находитсяuse loose;
Пол Тынг
12
Как и многие другие интересные и полезные вещи, Perl начинался как средство взлома, как инструмент для изобретателей. Позже он стал более популярным, и все большее количество неквалифицированных людей начали им пользоваться. Это когда вы начинаете думать, что что-то вроде use strictбыло хорошей идеей, но обратная совместимость уже стала для вас настоящей проблемой :-(
Daniel Böhmer
14
@JB Nizet, @Paul T. Фактически, включен use strict;по умолчанию, когда вы запрашиваете язык Perl 5.12 (или выше). Попробуй perl -e"use v5.012; $x=123;". no strict;фактически выключает его.
ikegami
1
Хотя, в конце концов, ваша точка зрения верна, чем чаще мы ее говорим, тем больше людей услышат. В последнее время были некоторые шумы о попытках сделать больше / лучше / современных руководств по Perl доступными, и, конечно, строгие / предупреждения будут в верхней части каждого из них. Что касается моего, я планирую размещать программное обеспечение в верхней части каждого сниппета, чтобы все новички видели его каждый раз
Джоэл Бергер
5
@JoelBerger Нет, на самом деле ничего подобного. Как я уже сказал, в названии есть только похожие слова. Это для обратной совместимости. это первое предложение в принятом ответе, как вы предлагаете это применимо к моему вопросу?
TLP

Ответы:

83

Для начала use strict;(и в меньшей степени use warnings;) помогает находить опечатки в именах переменных. Подобные ошибки допускают даже опытные программисты. Распространенный случай - забывают переименовать экземпляр переменной при очистке или рефакторинге кода.

Использование use strict; use warnings;перехватывает многие ошибки раньше, чем они могут быть обнаружены в противном случае, что упрощает поиск основных причин ошибок. Основной причиной может быть необходимость в проверке ошибок или валидации, и это может произойти независимо от навыков программиста.

Что хорошо в предупреждениях Perl, так это тем, что они редко бывают ложными, поэтому их использование практически бесплатно.


Связанное чтение: Зачем использовать my?

икегами
источник
2
@TLP, я не собираюсь проводить исследование, чтобы количественно оценить, насколько это помогает. Достаточно сказать, что они помогают безусловно.
ikegami
1
Тогда почему это необязательно, если у него так много преимуществ? Почему бы не включить его по умолчанию (как кто-то прокомментировал выше)? Это из соображений совместимости?
Жан
4
@Jean, обратная совместимость. Обратите внимание, что этот параметр use strict;включен по умолчанию, если вы используете версию языка 5.12 или новее ( use 5.012;).
ikegami
@Jean, если вы пишете простой скрипт, вы действительно не хотите получать предупреждения об именах обработчиков файлов или о том, что переменная не объявляется перед их использованием :-)
user2676847
28

По-видимому, use strictдолжен (должен) использоваться, когда вы хотите заставить perl правильно кодировать, что может быть принудительным объявлением, явным для строк и подпрограмм, то есть голыми словами или с осторожностью использовать ссылки. Примечание: если есть ошибки, use strict прервет выполнение, если используется.

Хотя use warnings;это поможет вам найти ошибки ввода в программе, например, вы пропустили точку с запятой, вы использовали elseif, а не elsif, вы используете устаревший синтаксис или функцию, что угодно в этом роде. Примечание: использование предупреждений предоставит только предупреждения и продолжит выполнение, т.е. не прервет выполнение.

В любом случае, будет лучше, если мы углубимся в детали, которые я уточняю ниже.

С perl.com (мой любимый):

используйте строгие "вары";

Это означает, что вы всегда должны объявлять переменные перед их использованием.

Если вы не объявите, вы, вероятно, получите сообщение об ошибке для необъявленной переменной.

Глобальный символ "$ variablename" требует явного имени пакета в строке 3 scriptname.pl

Это предупреждение означает, что Perl не совсем понимает, какова область видимости переменной. Таким образом, вам нужно четко указывать свои переменные, что означает либо объявление их, myчтобы они были ограничены текущим блоком, либо обращение к ним с их полным именем (например, $ MAIN :: variablename).

Таким образом, ошибка времени компиляции запускается, если вы пытаетесь получить доступ к переменной, которая не удовлетворяет хотя бы одному из следующих критериев:

  • Предопределено самим Perl, например @ARGV,% ENV и всеми глобальными переменными пунктуации, такими как $. или $ _.

  • Объявляется с помощью our (для глобального) или my (для лексического).

  • Импортировано из другого пакета. (Использование прагмы vars подделывает импорт, но вместо этого используйте наш.)

  • Полностью определен с использованием имени пакета и разделителя пакетов с двойным двоеточием.

используйте строгие «подписки»;

Рассмотрим две программы

# prog 1
   $a = test_value;
   print "First program: ", $a, "\n";
   sub test_value { return "test passed"; }
 Output: First program's result: test_value

# prog 2
   sub test_value { return "test passed"; }
   $a = test_value;
   print "Second program: ", $a, "\n";
 Output: Second program's result: test passed

В обоих случаях у нас есть подпрограмма test_value (), и мы хотим поместить ее результат в $ a. И все же, когда мы запускаем две программы, мы получаем два разных результата:

В первой программе, когда мы $a = test_value;подошли к этому моменту , Perl не знает ни одной подпрограммы test_value (), а test_value интерпретируется как строка test_value. Во второй программе определение test_value () идет перед $a = test_value;строкой. Perl считает test_value подвызовом.

Кстати, технический термин для отдельных слов, таких как test_value, которые могут быть подпрограммами или строками, в зависимости от контекста, - это голое слово . Обработка простых слов в Perl может сбивать с толку и вызывать ошибку в программе.

Ошибка - это то, с чем мы столкнулись в нашей первой программе. Помните, что Perl не будет ждать ее обнаружения test_value(), поэтому, поскольку он еще не видел test_value (), он предполагает, что вам нужна строка. Итак, если вы use strict subs;, это приведет к тому, что эта программа умрет с ошибкой:

Голое слово "test_value" не допускается, пока используются "строгие подпрограммы" в ./a6-strictsubs.pl, строка 3.

Решение этой ошибки:
1. Используйте круглые скобки, чтобы было ясно, что вы вызываете подпрограмму. Если Perl видит $ a = test_value () ;,
2. Объявите свой подпрограмм перед первым использованием

use strict;
sub test_value;  # Declares that there's a test_value() coming later ...
my $a = test_value;  # ...so Perl will know this line is okay.
.......
sub test_value { return "test_passed"; }

3. И если вы хотите использовать его как строку, укажите его в кавычках.

Итак, эта строгость заставляет Perl рассматривать все голые слова как синтаксические ошибки. * Голое слово - это любое голое имя или идентификатор, не имеющий другой интерпретации, обусловленной контекстом. (Контекст часто вызывается ближайшим ключевым словом или токеном, или предварительным объявлением рассматриваемого слова.) * Итак, если вы хотите использовать его как строку, заключите его в кавычки, а если вы хотите использовать его как вызов функции, объявите его заранее или используйте круглые скобки.

Голые слова опасны из-за такого непредсказуемого поведения. use strict; (or use strict 'subs';)делает их предсказуемыми, потому что голые слова, которые могут вызвать странное поведение в будущем, заставят вашу программу умереть, прежде чем они смогут нанести ущерб

Есть одно место, где можно использовать голые слова, даже когда вы включили строгие подпрограммы: когда вы назначаете хеш-ключи.

$hash{sample} = 6;   # Same as $hash{'sample'} = 6
%other_hash = ( pie => 'apple' );

Голые слова в хеш-ключах всегда интерпретируются как строки, поэтому нет двусмысленности.

используйте строгие ссылки;

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

use strict 'refs';

$ref = \$foo;       # Store "real" (hard) reference.
print $$ref;        # Dereferencing is ok.

$ref = "foo";       # Store name of global (package) variable.
print $$ref;        # WRONG, run-time error under strict refs.

использовать предупреждения;

Эта прагма с лексической областью видимости обеспечивает гибкий контроль над встроенными в Perl предупреждениями, как теми, которые генерируются компилятором, так и системой времени выполнения.

Откуда perldiag:

Таким образом, большинство предупреждающих сообщений из приведенных ниже классификаций, то есть W, D и S, можно контролировать с помощью warningsпрагмы.

(W) Предупреждение (необязательно)
(D) Устарение (включено по умолчанию)
(S) Серьезное предупреждение (включено по умолчанию)

Я перечислил некоторые из предупреждений, которые часто возникают, ниже по классификации. Подробную информацию о них и других сообщениях см. На perldiag.

(W) Предупреждение (необязательно):

Отсутствует аргумент в% s
Отсутствует аргумент для -% c
(Вы имели в виду &% s вместо этого?)
(Вы имели в виду "local" вместо "our"?)
(Вы имели в виду $ или @ вместо%?)
'% S 'не является ссылочной
длиной кода (), используемой в% s
Misplaced _ в номере

(D) Устарение (по умолчанию включено):

определено (@array) устарело
определено (% hash) устарело
Использование my () в ложном условном
$ # больше не поддерживается

(S) Серьезное предупреждение (по умолчанию включено)

elseif должен быть elsif
% s должен быть найден там, где ожидался оператор
(Отсутствует оператор перед% s?)
(Отсутствует точка с запятой в предыдущей строке?)
% s никогда не вводился
Оператор или точка с запятой отсутствуют перед% s
Проблема приоритета: открыть% s должен быть открыт (% s)
Несоответствие прототипа:% s vs% s
Предупреждение: использование "% s" без скобок является неоднозначным.
Невозможно открыть% s:% s

икегами
источник
10

Эти две прагмы могут автоматически определять ошибки в вашем коде.

Я всегда использую это в своем коде:

use strict;
use warnings FATAL => 'all';

FATALзаставляет код умирать при предупреждениях, как и strictделает.

Для получения дополнительной информации см. Строже с предупреждениями об использовании FATAL => 'all';

Также ... Стриктуры, по словам Сьюза

инструментальный
источник
На самом деле, вы должны отложить время FATAL => "all"выполнения до, назначив, $SIG{__WARN__} = sub { croak "fatalized warning @_" };иначе вы испортите компилятор, пытаясь сказать вам, что ему нужно.
tchrist
6
@tchrist: Это всегда работало для меня как есть и как задокументировано. Если вы обнаружили случай, когда он работает не так, как описано в документации, внесите исправления в документацию, используя perlbug.
toolic 06
9

По этому вопросу есть хорошая ветка на perlmonks .

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

угрюмый
источник
3

Источник :: Разные блоги

Использование будет экспортировать функции и имена переменных в основное пространство имен путем вызова функции modules import ().

Прагма - это модуль, который влияет на некоторые аспекты поведения perl во время компиляции или выполнения. Прагмы дают подсказки компилятору.

Используйте предупреждения - жалобы Perl на использование переменных только один раз, неправильное преобразование строк в числа,. Попытка записи в файлы, которые не открываются. Это происходит во время компиляции. Используется для контроля предупреждений.

Use strict - объявить область видимости переменных. Он используется для установки какой-то дисциплины в скрипте. Если в коде используются голые слова, они интерпретируются. Всем переменным должна быть задана область видимости, например my, our или local.

Рахул Редди
источник
1

Директива use strict указывает Perl выполнять дополнительную проверку во время компиляции вашего кода. Использование этой директивы сэкономит вам время на отладку кода Perl, поскольку она обнаруживает общие ошибки кодирования, которые в противном случае вы могли бы упустить.

МикасаАкерман
источник
0

Строгое и предупреждения убедитесь, что ваши переменные не глобальные.

Гораздо удобнее иметь переменные, уникальные для отдельных методов, чем отслеживать каждое имя переменной.

$ _ или отсутствие переменных для определенных функций также может быть полезно для более быстрого написания более компактного кода.

Однако, если вы не используете строгие правила и предупреждения, $ _ становится глобальным!

Андреас Эрлунд
источник
0
use strict;
use warnings;

Строгий режим и предупреждения - это режим для программы Perl. Это позволяет пользователю вводить код более свободно и, более того, код Perl будет выглядеть формально, а его стандарт кодирования будет эффективным.

предупреждения означают то же, что и -wв строке perl shebang, поэтому он предоставит вам предупреждения, сгенерированные программой perl, он будет отображаться в терминале

Дхана Говиндараджан
источник