perl - Uso de definido con Filehandle y while Loop
while-loop (3)
Digamos que tiene el siguiente archivo
4<LF>
3<LF>
2<LF>
1<LF>
0
( <LF>
representa un avance de línea. Observe la falta de nueva línea en la última línea).
Digamos que usas el código
while ($s = <>) {
chomp;
say $s;
}
Si Perl no hiciera nada mágico, la salida sería
4
3
2
1
Tenga en cuenta la falta de 0
, ya que la cadena 0
es falsa. defined
es necesario en el caso poco probable que
- Tiene un archivo de texto no estándar (línea nueva que falta).
- La última línea del archivo consiste en un único cero ASCII (0x30).
¡PERO ESPERE UN MINUTO! Si realmente ejecutó el código anterior con los datos anteriores, ¡vería 0
impreso! Lo que muchos no saben es que Perl traduce automágicamente
while ($s = <>) {
a
while (define($s = <>)) {
como se ve aquí:
$ perl -MO=Deparse -e''while($s=<DATA>) {}''
while (defined($s = <DATA>)) {
();
}
__DATA__
-e syntax OK
Entonces, técnicamente, ni siquiera necesita especificarlo en esta circunstancia específica.
Dicho esto, no puedo culpar a alguien por ser explícito en lugar de confiar en que Perl modifique automágicamente su código. Después de todo, Perl es (necesariamente) bastante específico en cuanto a qué secuencias de código cambiará. Tenga en cuenta la falta de defined
en el siguiente aunque se suponga que es un código equivalente:
$ perl -MO=Deparse -e''while((), $s=<DATA>) {}''
while ((), $s = <DATA>) {
();
}
__DATA__
-e syntax OK
Mientras leía un libro sobre la programación avanzada de Perl [1] , me encontré con este código:
while (defined($s = <>)) {
...
¿Hay algún motivo especial para usar defined
aquí? La documentación para Perlop dice:
En estas construcciones de bucle, el valor asignado (ya sea que la asignación sea automática o explícita) se prueba para ver si está definido. La prueba definida evita problemas donde la línea tiene un valor de cadena que Perl podría tratar como falso, por ejemplo, un
""
o un"0"
sin una línea nueva posterior. Si realmente quiere que esos valores terminen el ciclo, deberían probarse explícitamente: [...]
Entonces, ¿habría un caso de esquina o simplemente porque el libro es demasiado viejo y se agregó la prueba automática defined
en una versión reciente de Perl?
[1] Programación avanzada de perl, primera edición, Sriram Srinivasan. O''Reilly (1997)
Perl tiene muchos comportamientos implícitos, muchos más que la mayoría de los otros lenguajes. El lema de Perl es que hay más de uno para hacerlo, y como hay tanto comportamiento implícito, a menudo hay más de una forma de expresar exactamente lo mismo.
/foo/
lugar de$_ =~ m/foo/
$x = shift
lugar de$x = shift @_
while (defined($_=<ARGV>))
lugar dewhile(<>)
etc.
Qué expresiones utilizar son en gran medida una cuestión de sus estándares de codificación locales y preferencias personales. Las expresiones más explícitas le recuerdan al lector lo que realmente sucede bajo el capó. Esto puede mejorar o no la legibilidad del código, que depende de qué tan bien informado esté el público y si está utilizando expresiones idiomáticas bien conocidas.
En este caso, el comportamiento implícito es un poco más complicado de lo que parece. Algunas veces, perl
realizará implícitamente una prueba defined(...)
sobre el resultado del operador readline:
$ perl -MO=Deparse -e ''while($s=<>) { print $s }''
while (defined($s = <ARGV>)) {
print $s;
}
-e syntax OK
pero a veces no:
$ 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
Supongamos que le preocupan los casos de esquina que se supone que debe manejar este comportamiento implícito. ¿Ha cometido perlop
en la memoria para que comprenda cuándo Perl usa este comportamiento implícito y cuándo no? ¿Entiende las diferencias en este comportamiento entre Perl v5.14 y Perl v5.6? ¿Entenderán las personas que leen tu código?
De nuevo, no hay una respuesta correcta o incorrecta sobre cuándo usar las expresiones más explícitas, pero el uso de una expresión explícita es más fuerte cuando el comportamiento implícito es más esotérico.
while($line=<DATA>){
chomp($line);
if(***defined*** $line){
print "SEE:$line/n";
}
}
__DATA__
1
0
3
Pruebe el código con definido eliminado y verá el resultado diferente.