Подтвердить что ты не робот

В 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
}
4b9b3361

Ответ 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>) или особых случаях, связанных с ним.