Reputation: 8895
I've just encountered some very weird behavior that I really can't explain:
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";
The code above never prints "WHILE ENDED" even though it does seem to go out of the while loop when $TEST
>= 10.
But the following code does print "WHILE ENDED":
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 both tests, the initial value of $TEST
is 0.
Is the behavior of last
in do...while
different than in for
and while {...}
?
Upvotes: 20
Views: 12407
Reputation: 164769
TLP is right. The standard work around for this (I just hit it myself) is to wrap the do/while in a bare block which, counter-intuitively, does respect loop controls.
{ do {
last;
} while 1; }
The block outside will catch last
. If you want to handle next
you have to put the bloc inside.
do {{
next;
}} while 1;
The block inside will catch next
.
Unfortunately you can't do both.
Upvotes: 18
Reputation: 62099
A do
block with a looping modifier doesn't count as a real loop as far as next
, last
, and redo
are concerned. This is mentioned in perlsyn, where you'll find the tip Schwern mentioned about surrounding it with a bare block to make last
work. But that won't work with next
, because a bare block is only executed once, so next
acts like last
. To make next
work, you can put the bare block inside the do
, but then last
will act like next
.
If you need both next
and last
to work with a do ... while
, the easiest way is to use an infinite loop with the real condition in a continue
block. These 2 loops are equivalent, except that the second is a real loop, so it works with next
& last
:
do { ... } while condition;
while (1) { ... } continue { last unless condition };
Upvotes: 31
Reputation: 67900
From perldoc -f last:
"last" cannot be used to exit a block that returns a value such as "eval {}", "sub {}" or "do {}"
Upvotes: 22