perl language-design while-loop local

En Perl, ¿por qué la construcción ''while(<HANDLE>){...} `no localiza` $_`?



language-design while-loop (4)

Como nota al margen, solo escribimos while(<$fh>) porque Perl no tiene iteradores reales. Si Perl tuviera los iteradores adecuados, <$fh> devolvería uno. usaría eso para iterar una línea a la vez en lugar de agrupar todo el archivo en una matriz. No habría necesidad de while(<$fh>) o los casos especiales asociados con él.

¿Cuál fue la razón de diseño (o técnica) para que Perl no localice automáticamente $_ con la siguiente sintaxis:

while (<HANDLE>) {...}

Que se reescribe como:

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

Todas las otras construcciones que escriben implícitamente en $_ hacen de manera localizada ( for/foreach , map , grep ), pero con while , debe localizar explícitamente la variable:

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

Mi conjetura es que tiene algo que ver con el uso de Perl en el modo "Super-AWK" con interruptores de línea de comando, pero eso podría estar mal.

Entonces, si alguien sabe (o mejor aún, estuvo involucrado en la discusión del diseño del lenguaje), ¿podría compartir con nosotros el razonamiento detrás de este comportamiento? Más específicamente, ¿por qué permitir que el valor de $_ persista fuera del bucle se considera importante, a pesar de los errores que puede causar (lo cual tiendo a ver en todo el lugar en SO y en otro código de Perl)?

En caso de que no quede claro lo anterior, la razón por la cual $_ debe localizarse con while se muestra en este ejemplo:

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 }


Desde el thread en perlmonks.org:

Hay una diferencia entre foreach y while porque son dos cosas totalmente diferentes. foreach siempre se asigna a una variable cuando se repite en una lista, mientras while normalmente no lo hace. Es solo que while (<>) es una excepción y solo cuando hay un solo operador Diamond, hay una asignación implícita a $_ .

Y también:

Una posible razón por la while(<>) no localiza implícitamente $_ como parte de su magia es que a veces desea acceder al último valor de $_ fuera del bucle.


Especulación: Porque for y foreach son iteradores y valores de bucle sobre, mientras que while opera en una condición. En el caso de while (<FH>) la condición es que los datos se leyeron del archivo. El <FH> es lo que escribe a $_ , no el while . La prueba defined() implícita defined() es solo una opción para evitar que un código ingenuo termine el ciclo en una lectura de valor falso.

Para otras formas de bucles while, por ejemplo, while (/foo/) no querría localizar $_ .

Si bien estoy de acuerdo en que sería bueno que si while (<FH>) $_ localizado, tendría que ser un caso muy especial, que podría causar otros problemas al reconocer cuándo activarlo y cuándo no, muy parecido a las reglas para <EXPR> distingue es una lectura de identificador o una llamada a glob .


Sencillamente, while nunca se localiza. Ninguna variable está asociada con una construcción de while , por lo que ni siquiera tiene nada que localizar.

Si cambia alguna variable en la expresión de bucle while o en un cuerpo de bucle while, es responsabilidad suya realizar un alcance adecuado.