2011-10-25 17 views
14

我刚刚遇到了一些非常怪异的行为,我真的无法解释:的Perl做... while和最后一个命令

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

上面的代码永远不会打印“而结束”,尽管它似乎出门while循环时$TEST> = 10

但以下代码不打印“WHILE截至”:

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

在这两种测试中,初始值为0.

last的行为do...whileforwhile {...}的行为不同吗?

+0

我认为你说的“上面的代码”第二次,你实际上是指“的代码*之下*“ – TLP

回答

23

一个do块以循环调节剂并不至于nextlast算是真正的循环,redo关注。这在perlsyn中提到过,在这里你会发现Schwern提到的有关围绕它的提示,以便让last工作。但是这对next不起作用,因为裸块只执行一次,所以next的行为就像last。为使next正常工作,您可以将的空白块放入,do内,但last的行为将与next类似。

如果同时需要nextlastdo ... while工作,最简单的方法是在continue块使用一个无限循环使用的实际情况。这些2个循环是等效的,不同之处在于第二个是一个真正的循环,所以它的工作原理与next & last

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

详尽的解释,谢谢! – snoofkin

21

perldoc -f last

“最后” 不能用于退出返回这样的值, “EVAL {}” 的块, “亚{}” 或 “做{}”

14

TLP是正确的。这个标准的解决方案(我自己打的)就是将do/do包装在一个裸露的区块中,这个区块反直觉地尊重循环控制。

{ do { 
    last; 
} while 1; } 

在外面的区块将赶上last。如果您想处理next,则必须将该区块放入其中。

do {{ 
    next; 
}} while 1; 

里面的块将赶上next

不幸的是,你不能这样做。

+1

这将修复'last',但它不会修复'next'。对于裸块,这两者是等价的(因为裸块只能执行一次)。 – cjm

+0

@cjm很好。我发现你不能这样做。:-( – Schwern

+0

嗯,你可以这样做,但是你必须在外部块上贴一个标签,然后使用'last LABEL'。这只是要求bug,因为如果你忘记标签并输入'last'它会像'next'一样行动。 – cjm