2012-03-08 6 views
3

Во время чтения книги на передовой Perl программирование [1], я наткнулся этот код:Использование определяется с FILEHANDLE и в то время как Loop

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

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

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

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


[1] Advanced Perl Программирование, First Edition, Sriram Сринивазан. O'Reilly (1997)

ответ

7

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

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

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

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

т.д.

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

В этом случае неявное поведение немного сложнее, чем кажется.Иногда 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? Знают ли люди, читающие ваш код?

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

+1

Я также заметил, что ответ на фактический вопрос был похоронен в последнем абзаце. – darch

+0

Это очень ясно, когда '/ foo /' означает '$ _ = ~/foo /', но это не так ясно, когда '<>' означает 'defined ($ _ = <>)'. Я не считаю их одинаковыми. – ikegami

-1
while($line=<DATA>){ 
    chomp($line); 
if(***defined*** $line){ 
    print "SEE:$line\n"; 
} 
} 
__DATA__ 
1 
0 
3 

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

+0

Я знаю, что это будет по-другому, но это не так. Вопрос заключается в использовании 'defined' внутри цикла. – sidyll

+1

-1 для каждого из них, не отвечающих на вопрос и предоставляющих некомпилирующий код. – darch

+0

Perl автоматически заменяет 'while ($ line = )' with 'while (определено ($ line = ))', поэтому вы, очевидно, говорите о чем-то отличном от OP, если видите что-то другое. (См. Вывод 'perl -MO = Deparse -e'while ($ line = ) {} '') – ikegami

2

Допустим, вы имеете следующий файл

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

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

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

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

Если Perl не сделал ничего волшебного, выход был бы

4 
3 
2 
1 

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

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

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

while ($s = <>) { 

в

while (define($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