Ροή ελέγχου

last#

Εγκαταλείπει αμέσως έναν βρόχο, παραλείποντας το υπόλοιπο του σώματος και το μπλοκ continue.

Η last είναι το αντίστοιχο του break της C στην Perl. Μεταφέρει τον έλεγχο εκτός του περικλείοντος βρόχου στην εντολή που ακολουθεί. Οι υπόλοιπες εντολές της τρέχουσας επανάληψης δεν εκτελούνται, ούτε το μπλοκ continue του βρόχου - αυτή είναι η βασική διαφορά από τη next. Χωρίς όρισμα στοχεύει τον πιο εσωτερικό περικλείοντα while, until, for, foreach ή γυμνό μπλοκ· με LABEL στοχεύει έναν επώνυμο βρόχο πιο έξω.

Σύνοψη#

last
last LABEL
last EXPR       # LABEL computed at runtime, since 5.18

Τι επιστρέφεται#

Τίποτα. Η last εκτελεί έλεγχο ροής· δεν παράγει τιμή. Δεν μπορεί να χρησιμοποιηθεί για να επιστρέψει αποτέλεσμα από μπλοκ που κανονικά αποδίδει ένα, όπως eval { ... }, sub { ... }, ή do { ... }. Σε αυτά τα περιβάλλοντα είτε η κατασκευή δεν παράγει τιμή είτε το πρόγραμμα πεθαίνει με Can't "last" outside a loop block - δείτε Οριακές περιπτώσεις παρακάτω.

Στόχευση βρόχου με ετικέτα#

Χωρίς ετικέτα, η last αναφέρεται στον πιο εσωτερικό περικλείοντα βρόχο. Αυτό είναι συνήθως αυτό που θέλετε:

while (my $line = <$fh>) {
    last if $line =~ /^__END__$/;
    process($line);
}

Με μια ετικέτα μπορείτε να εγκαταλείψετε έναν εξωτερικό βρόχο μέσα από έναν εμφωλευμένο. Οι ετικέτες είναι συμβατικά εξ ολοκλήρου κεφαλαία:

OUTER: for my $row (@grid) {
    for my $cell (@$row) {
        last OUTER if $cell eq 'STOP';
    }
}
# control resumes here

Η last EXPR (Perl 5.18+) υπολογίζει την ετικέτα κατά τον χρόνο εκτέλεσης. Η EXPR πρέπει να αποτιμηθεί σε συμβολοσειρά που κατονομάζει μια περικλείουσα ετικέτα:

my $target = 'OUTER';
last $target;

Αλληλεπίδραση με μπλοκ continue#

Το μπλοκ continue ενός βρόχου εκτελείται κανονικά στο τέλος κάθε επανάληψης, περιλαμβανομένης της τελευταίας. Η last το παραλείπει - αυτή είναι η οριστική διαφορά της από τη next:

my $i = 0;
while ($i < 10) {
    last if $i == 3;
    print "body $i\n";
} continue {
    $i++;                 # runs after every iteration EXCEPT
                          # the one terminated by last
}
# prints body 0, body 1, body 2; then exits the loop.
# $i stays at 3 because continue did not fire the final time.

Αν θέλετε να εκτελεστεί η continue, χρησιμοποιήστε αντί γι” αυτό τη next με φύλακα, ή προωθήστε τον μετρητή πριν την last.

Συμπεριφορά σε εμφωλευμένους βρόχους#

Η last εγκαταλείπει μόνο έναν βρόχο τη φορά - τον πιο εσωτερικό, εκτός αν φέρει ετικέτα. Σε αυτό το παράδειγμα η εσωτερική last εγκαταλείπει τη for αλλά η while συνεχίζει να εκτελείται:

while (1) {
    for my $x (1 .. 5) {
        last if $x == 3;
    }
    # control lands here every iteration of the while
    last;                 # needed to exit the while as well
}

Για να ξετυλίξετε πολλά επίπεδα ταυτόχρονα, βάλτε ετικέτα στον εξωτερικό βρόχο και στοχεύστε τον:

SEARCH: for my $file (@files) {
    open my $fh, '<', $file or next;
    while (my $line = <$fh>) {
        if ($line =~ /$pattern/) {
            $found = $file;
            last SEARCH;  # exits both the while and the for
        }
    }
}

Τα γυμνά μπλοκ μετράνε ως βρόχοι#

Ένα γυμνό μπλοκ { ... } είναι, για σκοπούς ελέγχου ροής, ένας βρόχος που εκτελείται ακριβώς μία φορά. Η last μπορεί να εγκαταλείψει τέτοιο μπλοκ πρόωρα, που είναι ο ιδιωματικός τρόπος για να γράψετε «δοκίμασε μια ακολουθία ελέγχων, βγες στο πρώτο ταίριασμα»:

{
    last if $cached;
    recompute();
    store_in_cache();
}
# control continues here

Αυτή είναι η μόνη μορφή της last που δεν περιλαμβάνει επαναληπτική κατασκευή.

Παραδείγματα#

Σταματήστε την ανάγνωση αρχείου σε κενή γραμμή - το κλασικό ιδίωμα τερματιστή κεφαλίδας:

LINE: while (<$fh>) {
    last LINE if /^$/;
    push @header, $_;
}

Εύρεση-και-αναφορά σε δισδιάστατη δομή:

my $hit;
ROW: for my $r (0 .. $#grid) {
    for my $c (0 .. $#{ $grid[$r] }) {
        if ($grid[$r][$c] eq $needle) {
            $hit = [$r, $c];
            last ROW;
        }
    }
}

Πρόωρη έξοδος από γυμνό μπλοκ που χρησιμοποιείται ως ακολουθία try-once:

my $result;
{
    $result = $cache{$key}, last if exists $cache{$key};
    $result = compute($key);
    $cache{$key} = $result;
}

Υπολογισμένη ετικέτα (Perl 5.18+). Σπάνια απαιτείται, αλλά χρήσιμο όταν ο βρόχος-στόχος επιλέγεται δυναμικά:

my $level = $deep ? 'OUTER' : 'INNER';
OUTER: for (...) {
    INNER: for (...) {
        last $level if $done;
    }
}

Οριακές περιπτώσεις#

  • Παράνομη σε grep και map. Και οι δύο περιμένουν το μπλοκ τους να παράγει τιμή για κάθε στοιχείο εισόδου· η last το αποκλείει. Ο αναλυτής δέχεται τον κώδικα (το μπλοκ δεν είναι λεξιλογικά βρόχος μέσα από τον οποίο μπορεί να δει), αλλά η εκτέλεσή του πεθαίνει με Can't "last" outside a loop block. Φιλτράρετε με υπό συνθήκη μέσα στο μπλοκ αντί γι” αυτό, ή μεταβείτε σε ρητό βρόχο for.

  • Το do { ... } δεν είναι βρόχος. Η last μέσα σε do { ... } δεν τερματίζει τη do· ξετυλίγει στον κοντινότερο περικλείοντα πραγματικό βρόχο. Αν δεν υπάρχει, το πρόγραμμα πεθαίνει με Can't "last" outside a loop block. Για πρόωρη έξοδο από μια do που χρησιμοποιείται ως έκφραση, δείτε τα workarounds στο perlsyn υπό «Statement Modifiers» - τυπικά γυμνό μπλοκ συν last, ή βρόχος for μίας εκτέλεσης.

  • Η sub { ... } δεν είναι βρόχος. Η last μέσα σε σώμα sub δεν επιστρέφει από τη sub· ξετυλίγει πέρα από τη sub στον περικλείοντα βρόχο στον καλούντα. Χρησιμοποιήστε return για να φύγετε από μια sub.

  • Η last μέσα σε eval δεν διαφεύγει της eval. Η eval { ... } δεν είναι η ίδια βρόχος, οπότε η last κοιτάζει προς τα έξω πέρα από την eval για τον κοντινότερο περικλείοντα βρόχο και ξετυλίγει σε αυτόν. Η eval εγκαταλείπεται ως παρενέργεια αυτού του ξετυλίγματος, αλλά το $@ μένει κενό - δεν εγέρθηκε εξαίρεση. Αν η eval δεν έχει περικλείοντα βρόχο από πάνω, το πρόγραμμα πεθαίνει με Can't "last" outside a loop block. Για να φύγετε κανονικά από μια eval, αφήστε την ροή να τελειώσει ή χρησιμοποιήστε die (συλλαμβάνεται από την ίδια την eval) ή return (αν η eval βρίσκεται μέσα σε sub και θέλετε να φύγετε από τη sub).

  • Προτεραιότητα. Σε αντίθεση με τους περισσότερους ονομασμένους τελεστές, η last έχει την ίδια προτεραιότητα με την εκχώρηση και εξαιρείται από τον κανόνα «μοιάζει με συνάρτηση». Έτσι το last ("foo") . "bar" περνά το "foo" . "bar" ως ετικέτα, όχι μόνο το "foo". Χρησιμοποιήστε κενό, ή παραλείψτε τις παρενθέσεις, για να αποφύγετε εκπλήξεις:

    last LABEL;
    last "LABEL";
    
  • Άγνωστη ετικέτα. Η last NOPE όπου κανένας περικλείων βρόχος δεν φέρει την ετικέτα NOPE πεθαίνει με Label not found for "last NOPE". Αυτό είναι σφάλμα χρόνου εκτέλεσης, όχι μεταγλώττισης - η ετικέτα επιλύεται έναντι της δυναμικής στοίβας κλήσεων.

  • Η μορφή τροποποιητή βρόχου δεν έχει μπλοκ προς έξοδο. Το EXPR if COND και παρόμοιες μορφές τροποποιητή εντολής δεν είναι βρόχοι· η last μέσα στην έκφραση ξετυλίγει πέρα από αυτές.

Διαφορές από το upstream#

Πλήρως συμβατό με το upstream Perl 5.42.

Δείτε επίσης#

  • next - μεταβείτε στην επόμενη επανάληψη, εκτελώντας πρώτα το μπλοκ continue· το αντίστοιχο της last που κρατά τον βρόχο ζωντανό

  • redo - επανεκκινήστε την τρέχουσα επανάληψη χωρίς να επανελέγξετε τη συνθήκη και χωρίς να εκτελέσετε την continue

  • return - φύγετε από υπορουτίνα με τιμή· το σωστό εργαλείο όταν αναζητάτε την last μέσα σε sub { ... }

  • continue - το μπλοκ-ουραίο του βρόχου που η last παραλείπει και η next τιμά· διαβάστε τη σελίδα του για την τριμερή απεικόνιση των last / next / redo