Reputation: 2193
I have a 'do while' loop in Perl, and I need to break out if in the middle. I see last label;
is how I break out of loop, but I can't figure out where to add label. Here is my sample code.
my $count = 5;
do {
print $count;
if ( $count == 2 ) { last TAG; }
$count--;
} while ( $count > 0 );
TAG: print "out";
The above fails with "cannot find label". What am I doing wrong?
Upvotes: 5
Views: 10234
Reputation: 699
You can use goto instead of last.
my $count = 5;
do {
print $count;
if ( $count == 2 ) { goto TAG; }
$count--;
} while ( $count > 0 );
TAG: print "out";
Upvotes: 2
Reputation: 8532
Your tag is mis-placed. You haven't named the loop itself, you've simply placed a label somewhere that goto LABEL
could see. If you want to break out of the loop, you'll have to label the loop.
Additionally, do { ... } while
doesn't count as a loop. To make a loop that can be labeled, place it within its own set of braces:
TAG: { do {
body of the loop goes here.
last TAG if $condition;
} while( COND ) }
Upvotes: 1
Reputation: 385655
do BLOCK while COND;
is just do BLOCK
with a statement modifier attached. While it is special-cased to be bottom-tested, it is not a flow control statement like while (COND) BLOCK
. last
and friends only affect flow control statements, not statement modifiers.
$ perl -e'last while 1;'
Can't "last" outside a loop block at -e line 1.
One trick is to add a bare loop.
do {{
...;
next if ...;
...;
}} while COND;
or
{
do {
...;
last if ...;
...;
} while COND;
}
But that's fragile, error-prone and misleading. I prefer using an infinite loop as it is much safer and clearer.
while (1) {
...;
next if ...;
last if ...;
...;
last if !COND;
}
If you really dislike the infinite loop, you could also use the following, but I consider it more complex. (Two extra statements.)
for (my $loop=1; $loop; $loop=COND) {
...;
next if ...;
last if ...;
...;
}
Upvotes: 7
Reputation: 35198
Do not use the statement modifier form of do
:
do
BLOCK
does not count as a loop, so the loop control statementsnext
,last
, orredo
cannot be used to leave or restart the block. Seeperlsyn
for alternative strategies.
Instead, I recommend using a while
loop.
my $count = 5;
while ( $count > 0 ) {
print $count;
last if $count == 2;
$count--;
}
print "out";
Outputs:
5432out
If you need a construct that will always run one time before testing a condition, then use a while
loop of this form:
while (1) {
...
last if COND;
}
Upvotes: 8