Использование определений с помощью Filehandle и while Loop - PullRequest
3 голосов
/ 08 марта 2012

Читая книгу о продвинутом программировании на Perl (1) , я наткнулся на этот код:

while (defined($s = <>)) {
    ...

Есть ли какая-то особая причина для использования defined здесь?Документация для perlop гласит:

В этих конструкциях цикла назначенное значение (автоматическое или явное присвоение) затем проверяется, чтобы определитьопределено.Определенный тест позволяет избежать проблем, когда строка имеет строковое значение, которое Perl будет рассматривать как ложное, например "" или "0" без завершающего перевода строки.Если вы действительно хотите, чтобы такие значения заканчивали цикл, их следует проверить явно: [...]

Итак, будет ли угловой случай или это просто потому, что книга слишком стараяи автоматический тест defined был добавлен в последнюю версию Perl?


(1) Расширенное программирование на Perl, первое издание, Шрирам Шринивасан.О'Рейли (1997)

Ответы [ 3 ]

8 голосов
/ 08 марта 2012

В Perl много скрытого поведения, гораздо больше, чем в большинстве других языков.Девиз Perl: «Есть больше, чем один, и потому, что существует так много неявного поведения, часто существует больше, чем один способ выразить одно и то же».

/foo/ вместо $_ =~ m/foo/

$x = shift вместо $x = shift @_

while (defined($_=<ARGV>)) вместо while(<>)

и т. Д.

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

В этом случае неявное поведение немного сложнее, чемпохоже на то.Иногда perl будет неявно выполнять defined(...) тест на результат оператора readline:

$ perl -MO=Deparse -e 'while($s=<>) { print $s }'
while (defined($s = <ARGV>)) {
    print $s;
}
-e syntax OK

, но иногда это не будет:

$ perl -MO=Deparse -e 'if($s=<>) { print $s }'
if ($s = <ARGV>) {
    print $s;
}
-e syntax OK

$ perl -MO=Deparse -e 'while(some_condition() && ($s=<>)) { print $s }'
while (some_condition() and $s = <ARGV>) {
    print $s;
}
-e syntax OK

Предположим, что вы обеспокоеныо угловых случаях, которые это неявное поведение должно обрабатывать.Вы посвятили perlop памяти, чтобы понять, когда Perl использует это неявное поведение, а когда нет?Понимаете ли вы различия в этом поведении между Perl v5.14 и Perl v5.6?Понимают ли люди, читающие ваш код?

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

3 голосов
/ 09 марта 2012

Скажем, у вас есть следующий файл

4<LF>
3<LF>
2<LF>
1<LF>
0

(<LF> представляет перевод строки. Обратите внимание на отсутствие новой строки в последней строке.)

Скажем, вы используете код

while ($s = <>) {
   chomp;
   say $s;
}

Если бы Perl не делал ничего волшебного, результат был бы

4
3
2
1

Обратите внимание на отсутствие 0, поскольку строка 0 имеет значение false. defined необходим в маловероятном случае, если

  • У вас нестандартный текстовый файл (отсутствует завершающий перевод строки).
  • Последняя строка файла состоит из одного ноля ASCII (0x30).

НО ЖДУТЕ МИНУТУ! Если вы действительно запустили приведенный выше код с указанными выше данными, вы увидите 0 напечатано! Многие не знают, что Perl автоматически переводит

while ($s = <>) {

до

while (defined($s = <>)) {

как видно здесь:

$ perl -MO=Deparse -e'while($s=<DATA>) {}'
while (defined($s = <DATA>)) {
    ();
}
__DATA__
-e syntax OK

Так что технически вам даже не нужно указывать defined в этом очень специфическом случае.

Тем не менее, я не могу винить кого-то за то, что он явный, вместо того, чтобы полагаться на Perl, автоматически изменяющий их код. В конце концов, Perl (обязательно) весьма специфичен в отношении того, какие последовательности кода он изменит. Обратите внимание на отсутствие defined в следующем, даже если это предположительно эквивалентный код:

$ perl -MO=Deparse -e'while((), $s=<DATA>) {}'
while ((), $s = <DATA>) {
    ();
}
__DATA__
-e syntax OK
0 голосов
/ 08 марта 2012
while($line=<DATA>){
    chomp($line);
if(***defined*** $line){
    print "SEE:$line\n";
}
}
__DATA__
1
0
3

Попробуйте код с определенным удаленным, и вы увидите другой результат.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...