2011-10-25 8 views
14

he acabamos de encontrar un comportamiento muy raro que realmente no puedo explicar:Perl do ... while y última orden

do { 
    my $qry = $self->getHTMLQuery(undef, $mech->content()); 
    next if (!defined($qry)); 

    push(
     @prods, 
     map { 'http://www.XXXXYYYX.com'.$_->attr('href') } 
      $qry->query('div.prodInfo div.prodInfoBox a.prodLink.GridItemLink') 
    ); 

    $qry->delete(); 
    $TEST++; 

    last if ($TEST >= 10); 

} while(eval { $mech->follow_link(class => 'jump next') }); 

print "WHILE ENDED\n"; 

El código anterior imprime nunca "mientras TERMINADO" a pesar de que parece para salir del bucle mientras que cuando $TEST> = 10.

Pero el código siguiente se imprime "mientras TERMINADO":

do { 
    my $qry = $self->getHTMLQuery(undef, $mech->content()); 
    next if (!defined($qry)); 

    push(
     @prods, 
     map { 'http://www.XXXXYYYX.com'.$_->attr('href') } 
      $qry->query('div.prodInfo div.prodInfoBox a.prodLink.GridItemLink') 
    ); 

    $qry->delete(); 
    $TEST++; 

} while(eval { $mech->follow_link(class => 'jump next') } && $TEST <= 10); 

print "WHILE ENDED\n"; 

En ambas pruebas, el valor inicial de $TEST es 0.

¿El comportamiento de last en do...while es diferente que en for y while {...}?

+0

Asumo la segunda vez que dicen "el código de arriba", en realidad se refiere a "el código * por debajo * " – TLP

Respuesta

23

Un bloque do con un modificador de bucle no cuenta como un bucle verdadera medida de lo next, last, y redo se refiere. Esto se menciona en perlsyn, donde encontrará la sugerencia de Schwern sobre rodearlo con un bloque desnudo para que last funcione. Pero eso no funcionará con next, porque un bloque desnudo solo se ejecuta una vez, por lo que next actúa como last. Para hacer que next funcione, puede colocar el bloque vacío dentro dedo, pero luego last actuará como next.

Si necesita tanto next y last trabajar con un do ... while, la forma más fácil es usar un bucle infinito con la condición real en un bloque continue. Estos 2 bucles son equivalentes, excepto que el segundo es un circuito real, por lo que funciona con next & last:

do { ... } while condition; 
while (1) { ... } continue { last unless condition }; 
+0

Explicación exhaustiva, ¡gracias! – snoofkin

21

De perldoc -f last:

"último" no se puede utilizar para salir de un bloque que devuelve un valor como "eval {}", "sub {}" o "do {}"

14

TLP tiene razón. La solución estándar para esto (yo solo lo toco) es envolver el do/while en un bloque desnudo que, de manera intuitiva, respeta los controles de bucle.

{ do { 
    last; 
} while 1; } 

El bloque fuera cogerá last. Si quiere manejar next, tiene que colocar el bloque dentro.

do {{ 
    next; 
}} while 1; 

El bloque dentro cogerá next.

Desafortunadamente no puede hacer ambas cosas.

+1

Eso arreglará el' last' pero no arreglará el 'next'. Con un bloque desnudo, esos dos son equivalentes (ya que los bloques desnudos solo se ejecutan una vez). – cjm

+0

@cjm Buena captura. Y descubrí que no puedes hacer ambas cosas.:-( – Schwern

+0

Bueno, podrías, pero tendrías que poner una etiqueta en el bloque externo y luego usar 'last LABEL '. Y eso es solo preguntar por los errores, porque si olvidas la etiqueta y escribes' last', en su lugar actuará como 'próximo '. – cjm

Cuestiones relacionadas