В Perl, почему `while (<HANDLE>) {...}` построить не локализовать `$ _`?
Какова была конструктивная (или техническая) причина для 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
}
Ответы
Ответ 1
Из потока на perlmonks.org:
Существует разница между foreach
и while
, потому что они два полностью разные вещи. foreach
всегда присваивает переменной при циклировании над списком, тогда как while
обычно не делает. Это просто, что while (<>)
исключение, и только когда есть оператор с одним бриллиантом неявное присвоение $_
.
А также:
Одна из возможных причин почему while(<>)
не косвенно локализует $_
как частью его магии является то, что иногда вы хотите получить доступ к последнему значению $_
вне цикла.
Ответ 2
Проще говоря, while
никогда не локализуется. Никакая переменная не связана с конструкцией while
, поэтому ей даже нечего локализовать.
Если вы измените какую-либо переменную в выражении цикла while
или в теге цикла while
, это ваша ответственность, чтобы адекватно охватить ее.
Ответ 3
Спекуляция: поскольку for
и foreach
являются итераторами и циклическими значениями, а while
работает с условием. В случае while (<FH>)
условие состоит в том, что данные считывались из файла. <FH>
- это то, что пишет $_
, а не while
. Неявный тест defined()
- это просто возможность избежать наивного кода от завершения цикла при чтении ложного значения.
Для других форм циклов while
, например. while (/foo/)
вы не захотите локализовать $_
.
Хотя я согласен с тем, что было бы неплохо, если бы while (<FH>)
localized $_
, это был бы особый случай, который мог бы вызвать другие проблемы с распознаванием, когда его запускать и когда это не так, как правила для <EXPR>
отличия - это чтение дескриптора или вызов glob
.
Ответ 4
В качестве побочной заметки мы пишем только while(<$fh>)
, потому что у Perl нет реальных итераторов. Если бы у Perl были правильные итераторы, <$fh>
вернул бы один. for
будет использовать это для повторения строки за раз, а не для выделения всего файла в массив. Нет необходимости в while(<$fh>)
или особых случаях, связанных с ним.