2008-10-21 10 views
10

no necesito esto, obviamente; Solo tengo curiosidad sobre lo que está pasando aquí. ¿Me falta algo algo simple? ¿Puedo confiar en este comportamiento en todas las versiones de Perl)

Perl v5.8.8:?

%h = (0=>'zero', 1=>'one', 2=>'two'); 
while ($k = each %h) { 
    $v = delete $h{$k}; 
    print "deleted $v; remaining: @h{0..2}\n"; 
} 

salidas

deleted one; remaining: zero two 
deleted zero; remaining: two 
deleted two; remaining: 

man perlfunc (cada uno) no explica por qué el bucle while continúa cuando $k se asigna 0. el código se comporta como si la condición en la while bucle eran ($k = each %h, defined $k).

Si la condición del bucle se cambia realmente a ($k = each %h, $k) entonces en efecto, parada en $k = 0 como se esperaba.

También se detiene en $k = 0 para el siguiente reimplementación de each:

%h = (0=>'zero', 1=>'one', 2=>'two'); 
sub each2 { 
    return each %{$_[0]}; 
} 
while ($k = each2 \%h) { 
    $v = delete $h{$k}; 
    print "deleted $v; remaining: @h{0..2}\n"; 
} 

salidas sólo:

deleted one; remaining: zero two 

Respuesta

29

Estás llamando each en contexto escalar, así que no es de trabajo a causa de una enumerar el valor de retorno.

al igual que

while ($line = <FILE>) 

es especial con carcasa para añadir un defined implícita, por lo que es

while ($key = each %hash) 

En 5.8.8, lo que sucede en op.c, desde 3760 hasta 3766 líneas:

case OP_SASSIGN: 
    if (k1->op_type == OP_READDIR 
     || k1->op_type == OP_GLOB 
     || (k1->op_type == OP_NULL && k1->op_targ == OP_GLOB) 
     || k1->op_type == OP_EACH) 
    expr = newUNOP(OP_DEFINED, 0, expr); 
    break; 

No estoy seguro de si esto se aplica a todas las versiones de Perl 5.

Ver también: When does while() test for defined vs truth en PerlMonks. No puedo encontrar dónde se menciona esto en los documentos de Perl (se menciona el caso <FILE>, pero no veo el caso each).

0

Gracias, cjm. Estaba claro algún tipo de adición implícita de un defined estaba pasando así por pegote pero no donde se documentados. Ahora, al menos, conozco los casos limitados en los que se aplica el tratamiento especial .

embargo, la información debe estar en la documentación perlfunc, no sólo al código fuente de Perl!

6

CJM es correcto. Solo quiero agregar que cuando te encuentras con cosas raras como esta, a menudo es útil ejecutar tu código a través del B::Deparse para ver cómo entendió Perl tu código. Me gusta usar el modificador -p para mostrar los errores de precedencia también.

$ perl -MO=Deparse,p your_example.plx 
(%h) = (0, 'zero', 1, 'one', 2, 'two'); 
while (defined($k = each %h)) { 
    $v = delete $h{$k}; 
    print "deleted $v; remaining: @h{0..2}\n"; 
} 
your_example.plx syntax OK 
Cuestiones relacionadas