سؤال

According to the perl manual for for last (http://perldoc.perl.org/functions/last.html), last can't be used to break out of do {} loops, but it doesn't mention an alternative. The script I'm maintaining has this structure:

do {
    ...
    if (...) 
    {
        ...
        last;
    }
} while (...);

and I'm pretty sure he wants to go to the end of the loop, but its actually exiting the current subroutine, so I need to either change the last or refactor the whole loop if there is a better way that someone can recommend.

هل كانت مفيدة؟

المحلول

do BLOCK while (EXPR) is funny in that do is not really a loop structure. So, last, next, and redo are not supposed to be used there. Get rid of the last and adjust the EXPR to evaluate false when that situation is found. Also, turn on strict, which should give you at least a warning here.

نصائح أخرى

Wrap the do "loop" in a bare block (which is a loop):

{
    do {
        ...
        if (...) 
        {
            ...
            last;
        }
    } while (...);
}

This works for last and redo, but not next; for that place the bare block inside the do block:

do {{
    ...
    if (...) 
    {
        ...
        next;
    }
    ...
}} while (...);

Never a fan of do/while loops in Perl. the do isn't really a loop which is why last won't break out of it. In our old Pascal daze you couldn't exit a loop in the middle because that would be wrong according to the sage Niklaus "One entrance/one exit" Wirth. Therefore, we had to create an exit flag. In Perl it'd look something like this:

my $endFlag = 0;
do {
    ...
    if (...) 
    {
        ...
        $endFlag = 1;
    }
} while ((...) and (not $endFlag));

Now, you can see while Pascal never caught on.

Why not just use a while loop?

while (...) {
  ...
  if (...) {
    last;
  }
}

You might have to change your logic slightly to accommodate the fact that your test is at the beginning instead of end of your loop, but that should be trivial.

By the way, you actually CAN break out of a Pascal loop if you're using Delphi, and Delphi DID catch on for a little while until Microsoft wised up and came out with the .net languages.

@ "http://perldoc.perl.org/functions/last.html": last cannot be used to exit a block that returns a value such as eval {} , sub {} or do {} , and should not be used to exit a grep() or map() operation.

So, use a boolean in the 'while()' and set it where you have 'last'...

Late to the party - I've been messing with for(;;) recently. In my rudimentary testing, for conditional expressions A and B, what you want to do with:

do {
    last if A;
} while(B);

can be accomplished as:

for(;; B || last) {
    last if A;
}

A bit ugly, but perhaps not more so than the other workarounds :) . An example:

my $i=1; 
for(;; $i<=3 || last) { 
    print "$i ";
    ++$i;
}

Outputs 1 2 3. And you can combine the increment if you want:

my $i=1;
for(;; ++$i, $i<=3 || last) { 
    print "$i ";
}

(using || because it has higher precedence than ,)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top