2011-10-25 13 views
14

Ho appena incontrato un comportamento molto strano che davvero non riesco a spiegare:Perl do ... while e ultimo comando

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"; 

Il codice di cui sopra mai stampe "MENTRE CHIUSO", anche se lo fa sembrare uscire dal ciclo while quando $TEST> = 10.

Ma il codice seguente viene stampato "dURANTE CHIUSO":

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"; 

In entrambe le prove, il valore iniziale di $TEST è 0.

Il comportamento di last è do...while diverso da for e while {...}?

+0

suppongo la seconda volta che si dice "il codice di cui sopra", in realtà si intende "il codice * qui sotto * " – TLP

risposta

23

Un do blocco con un modificatore loop non conta come un vero e proprio ciclo quanto next, last e redo sono interessati. Questo è menzionato in perlsyn, dove troverai la punta che Schwern ha menzionato riguardo al fatto di circondarlo con un blocco nuda per fare funzionare last. Ma questo non funzionerà con next, perché un blocco nudo viene eseguito solo una volta, quindi next si comporta come last. Per eseguire il lavoro next, è possibile inserire il blocco nuda all'interno dello dello do, ma successivamente lo last si comporterà come next.

Se avete bisogno di entrambi next e last di lavorare con un do ... while, il modo più semplice è quello di utilizzare un ciclo infinito con la condizione reale in un blocco continue. Questi 2 loop sono equivalenti, se non che il secondo è un vero e proprio ciclo, in modo che funziona con next & last:

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

Spiegazione esauriente, grazie! – snoofkin

21

Da perldoc -f last:

"ultimo" non può essere utilizzato per uscire da un blocco che restituisce un valore come "eval {}", "sub {}" o "do {}"

14

TLP ha ragione. Lo standard su cui lavorare per questo (l'ho appena colpito io stesso) è di avvolgere il do/while in un blocco nuda che, in modo intuitivo, rispetta i controlli del ciclo.

{ do { 
    last; 
} while 1; } 

Il blocco esterno prenderà last. Se vuoi gestire next devi mettere dentro il blocco.

do {{ 
    next; 
}} while 1; 

Il blocco interno prenderà next.

Purtroppo non è possibile fare entrambe le cose.

+1

Questo risolverà l'ultimo', ma non risolverà il 'prossimo'. Con un blocco nuda, questi due sono equivalenti (poiché i blocchi nudi vengono eseguiti una sola volta). – cjm

+0

@cjm Buona cattura. E ho scoperto che non puoi fare entrambe le cose.:-( – Schwern

+0

Beh, tu _could_, ma dovresti mettere un'etichetta sul blocco esterno e poi usare 'last LABEL'. E questo è solo chiedere bug, perché se dimentichi l'etichetta e scrivi solo' last', agirà come 'next' invece. – cjm