В Perl, почему конструкция while (<HANDLE>) {...} `не локализует` $ _`? - PullRequest
23 голосов
/ 31 марта 2011

По какой причине (или по техническим причинам) Perl не локализовал $_ автоматически со следующим синтаксисом:

while (<HANDLE>) {...}

, который переписывается как:

while (defined( $_ = <HANDLE> )) {...}

Вседругие конструкции, которые неявно записывают в $_, делают это локализованным способом (for/foreach, map, grep), но с while вы должны явно локализовать переменную:

local $_;
while (<HANDLE>) {...}

Я предполагаю, что это как-то связано с использованием Perl в режиме «Super-AWK» с переключателями командной строки, но это может быть неправильно.

Так что, если кто-нибудь знает (или, что еще лучше, участвовал вобсуждение языкового дизайна), не могли бы вы поделиться с нами причинами такого поведения?Более конкретно, почему было позволено сохранять значение $_ вне цикла, которое считается важным, несмотря на ошибки, которые оно может вызывать (что я обычно вижу повсюду в SO и в другом коде Perl)?


В случае, если из приведенного выше не ясно, причина, по которой $_ должен быть локализован с while, показана в этом примере:

sub read_handle {
    while (<HANDLE>) { ... }
}

for (1 .. 10) {
     print "$_: \n"; # works, prints a number from 1 .. 10
     read_handle;
     print "done with $_\n";  # does not work, prints the last line read from
                              # HANDLE or undef if the file was finished
}

Ответы [ 4 ]

14 голосов
/ 31 марта 2011

Из потока на perlmonks.org:

Существует разница между foreach и while, потому что это две совершенно разные вещи.foreach всегда присваивается переменной при циклическом просмотре списка, в то время как while обычно нет.Просто while (<>) является исключением, и только при наличии одного алмазного оператора существует неявное присвоение $_.

А также:

Одна из возможных причинпричина того, что while(<>) не является неявной локализацией $_ как часть его магии, заключается в том, что иногда вы хотите получить доступ к последнему значению $_ вне цикла.

7 голосов
/ 01 апреля 2011

Проще говоря, while никогда не локализуется.Ни одна переменная не связана с конструкцией while, поэтому ей даже нечего локализовать.

Если вы измените какую-либо переменную в выражении цикла while или в теле цикла while,Вы несете ответственность за его адекватное определение.

2 голосов
/ 01 апреля 2011

Спекуляция: поскольку for и foreach являются итераторами и значениями циклического перехода, тогда как while работает с условием. В случае while (<FH>) условие состоит в том, что данные были прочитаны из файла. <FH> - это то, что пишет в $_, а не while. Неявный defined() тест - это просто возможность предотвратить наивный код от завершения цикла при чтении ложного значения.

Для других форм петель while, например, while (/foo/) вы не хотите локализовать $_.

Хотя я согласен с тем, что было бы неплохо, если бы while (<FH>) локализовал $_, это был бы особый случай, который мог бы вызвать другие проблемы с распознаванием того, когда его запускать, а когда нет, во многом как правила для <EXPR>, отличающихся тем, что они прочитали дескриптор или вызов glob.

0 голосов
/ 04 апреля 2011

В качестве примечания мы пишем while(<$fh>), потому что в Perl нет реальных итераторов.Если бы в Perl были правильные итераторы, <$fh> вернул бы один.for будет использовать это для итерации строки за раз, вместо того, чтобы слить весь файл в массив.Не будет необходимости в while(<$fh>) или особых случаях, связанных с ним.

...