user3606175
user3606175

Reputation: 2193

Breaking out of a 'do while' loop in Perl

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

Answers (4)

marneborn
marneborn

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

LeoNerd
LeoNerd

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

ikegami
ikegami

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

Miller
Miller

Reputation: 35198

Do not use the statement modifier form of do:

do BLOCK does not count as a loop, so the loop control statements next, last, or redo cannot be used to leave or restart the block. See perlsyn 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

Related Questions