Ροή ελέγχου

catch#

Χειρίζεται μια εξαίρεση που εκτοξεύθηκε από προηγούμενο μπλοκ try.

Η catch είναι το δεύτερο μισό της κατασκευής try/catch. Δεν είναι αυτόνομη εντολή: ακολουθεί ένα μπλοκ try, δηλώνει μια λεξιλογική VAR για να λάβει την τιμή της εξαίρεσης, και εκτελεί το BLOCK της μόνο όταν το μπλοκ try πέθανε. Αν το μπλοκ try ολοκληρώθηκε κανονικά, το μπλοκ catch παραλείπεται. Ο έλεγχος συνεχίζει τότε στην εντολή που ακολουθεί ολόκληρη την κατασκευή (ή στο μπλοκ finally, αν υπάρχει).

Αυτή η σύνταξη πρέπει να ενεργοποιηθεί με use feature 'try'. Οι try και catch δεν είναι πειραματικές από την Perl 5.40 και μετά.

Σύνοψη#

try BLOCK catch (VAR) BLOCK
try BLOCK catch (VAR) BLOCK finally BLOCK

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

Η catch δεν είναι κλήση συνάρτησης και δεν έχει επιστροφή με την έννοια της έκφρασης. Όπως άλλες κατασκευές ροής ελέγχου, η τιμή ολόκληρης της try/catch είναι η τιμή του μπλοκ που εκτελέστηκε τελευταίο - χρήσιμο μέσα σε μπλοκ do ή ως ουραία έκφραση μιας υπορουτίνας:

my $value = do {
    try {
        fetch_thing(@args);
    }
    catch ($e) {
        warn "fetch failed: $e";
        $DEFAULT;
    }
};

Αν η try εκτελέστηκε μέχρι το τέλος, η κατασκευή αποδίδει την τελευταία τιμή του μπλοκ try και η VAR δεν δένεται ποτέ. Αν η try πέθανε, η κατασκευή αποδίδει την τελευταία τιμή του μπλοκ catch.

Η δήλωση VAR#

The parentheses after catch are mandatory and must contain exactly one scalar variable declaration. It behaves like a my declaration

  • the my keyword is implicit, as in subroutine signatures:

catch ($e)  { ... }         # $e is a new lexical
catch (my $e) { ... }       # syntax error - 'my' is already implied

Η VAR έχει εμβέλεια μόνο μέσα στο μπλοκ catch. Δεν είναι ορατή στο προηγούμενο μπλοκ try, σε οποιοδήποτε επόμενο μπλοκ finally, ούτε μετά την κατασκευή. Η τιμή της είναι ό,τι εκτόξευσε το μπλοκ try - μια συμβολοσειρά, μια λίστα που μετατράπηκε σε συμβολοσειρά, ή μια αναφορά, τυπικά ένα blessed αντικείμενο εξαίρεσης. Δείτε την die για το πώς παράγεται η τιμή της εξαίρεσης.

Σε αντίθεση με την eval, η catch δεν διαβάζει ούτε καθαρίζει το $@· η εξαίρεση ταξιδεύει απευθείας μέσω της VAR. Το $@ παραμένει ανέγγιχτο από την κατασκευή.

Καθολική κατάσταση που επηρεάζει#

Η ίδια η catch δεν επηρεάζει καμία ειδική μεταβλητή. Η κατασκευή try/catch στο σύνολό της αφήνει το $@ αμετάβλητο - σκόπιμη απόκλιση από την eval που έχει σκοπό να αποτρέψει τους καλούντες από το να συγχέουν τα δύο ιδιώματα. Αν χρειάζεστε επιθεώρηση τύπου $@, χρησιμοποιήστε την eval αντί γι” αυτό.

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

Σύλληψη μιας απλής εξαίρεσης συμβολοσειράς και αναφορά της:

use feature 'try';

try {
    risky();
}
catch ($e) {
    warn "risky failed: $e";
}

Επιθεώρηση ενός δομημένου αντικειμένου εξαίρεσης:

try {
    process($record);
}
catch ($e) {
    if (ref($e) && $e->isa('My::NotFound')) {
        return;                       # missing is fine
    }
    die $e;                           # re-throw everything else
}

Επανεκπομπή αμετάβλητης με die. Επειδή η catch δεν αγγίζει το $@, επανεκπέμπετε τη μεταβλητή που δεσμεύσατε, όχι το $@:

try {
    step();
}
catch ($e) {
    log_error($e);
    die $e;                           # propagates to the next handler
}

Παραγωγή τιμής από την κατασκευή χωρίς return. Η χρήση της return μέσα σε try ή catch επιστρέφει από την περικλείουσα υπορουτίνα, όχι από την κατασκευή - δείτε Οριακές περιπτώσεις:

sub safe_parse {
    my ($text) = @_;
    try {
        parse($text);
    }
    catch ($e) {
        warn "parse error: $e";
        undef;                        # value of the catch block
    }
}

Ένα μπλοκ catch που το ίδιο πεθαίνει - η νέα εξαίρεση διαδίδεται προς τα έξω στον επόμενο περικλείοντα χειριστή (try/catch, eval, ή έξοδος προγράμματος):

try {
    open_db();
}
catch ($e) {
    cleanup();
    die "open_db failed: $e";         # thrown from inside catch
}

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

  • Δεν μπορεί να σταθεί μόνη της. Το catch (VAR) { ... } χωρίς προηγούμενο μπλοκ try είναι συντακτικό σφάλμα. Η catch αναλύεται ως μέρος της κατασκευής try, όχι ως ανεξάρτητη δεσμευμένη λέξη.

  • Ακριβώς ένα βαθμωτό στις παρενθέσεις. Οι παρενθέσεις είναι υποχρεωτικές, πρέπει να δηλώνουν ακριβώς ένα βαθμωτό, και η my υπονοείται. Το catch { ... } χωρίς παρενθέσεις είναι συντακτικό σφάλμα.

  • Η VAR έχει εμβέλεια μπλοκ. Υπάρχει μόνο μέσα στο μπλοκ catch. Ένα μπλοκ finally που ακολουθεί δεν τη βλέπει.

  • Οι ψευδείς εξαιρέσεις εξακολουθούν να ενεργοποιούν τον χειριστή. Η try διακρίνει το «πέθανε» από το «ολοκληρώθηκε κανονικά» με μια σημαία που τίθεται κατά το ξετύλιγμα, όχι με την αληθότητα της τιμής εξαίρεσης. Τα die 0, die "" και die undef εισέρχονται όλα στο μπλοκ catch· η VAR λαμβάνει την τιμή όπως εκτοξεύθηκε (με τον συνηθισμένο εξαναγκασμό της die του undef σε "Died at ...").

  • Το $@ δεν τίθεται. Κώδικας που αναζητά το $@ μέσα σε μπλοκ catch διαβάζει το $@ του καλούντος, όχι την εξαίρεση που μόλις συνέλαβε. Χρησιμοποιήστε την VAR.

  • Ένα μπλοκ catch μπορεί να πεθάνει. Οι εξαιρέσεις που εγείρονται μέσα στο catch δεν συλλαμβάνονται εκ νέου από την ίδια κατασκευή. Διαδίδονται στον επόμενο περικλείοντα χειριστή. Αυτός είναι ο μηχανισμός για επανεκπομπή (die $e) και για αναφορά αποτυχιών καθαρισμού από τον ίδιο τον χειριστή.

  • Η return μέσα στο catch επιστρέφει από την περικλείουσα υπορουτίνα, όχι από το μπλοκ catch. Αυτό διαφέρει από το eval BLOCK, όπου η return θα έβγαινε μόνο από την eval. Για να αποδώσετε τιμή από την κατασκευή, χρησιμοποιήστε την τελική έκφραση του μπλοκ αντί της return.

  • Τα στοιχεία ελέγχου βρόχου (last, next, redo) μέσα στο catch στοχεύουν περικλείοντα βρόχο, όχι την κατασκευή. Η κατασκευή try/catch δεν αποτελεί η ίδια βρόχο.

  • Η caller() δεν βλέπει το πλαίσιο catch. Επειδή η catch δεν παρεμποδίζει την return, είναι αόρατη στην caller, όπως είναι και τα while ή foreach.

  • Συνδυάζεται μόνο με την αμέσως προηγούμενη try. Δεν μπορείτε να έχετε δύο μπλοκ catch, ούτε να τοποθετήσετε εντολές μεταξύ try και catch. Το προαιρετικό μπλοκ finally, αν υπάρχει, πρέπει να ακολουθεί την catch.

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

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

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

  • try - το μπλοκ του οποίου την αποτυχία χειρίζεται αυτή η catch· πάντοτε συνδυάζεται με ακριβώς μία catch

  • finally - προαιρετικό τρίτο μπλοκ που εκτελείται ανεξάρτητα από το αν πέθανε το μπλοκ try· δεν μπορεί να κάνει return ή να χρησιμοποιήσει στοιχεία ελέγχου βρόχου

  • die - παράγει την τιμή εξαίρεσης που λαμβάνει η VAR· χρησιμοποιήστε την μέσα στο catch για επανεκπομπή

  • eval - παλαιότερο ιδίωμα χειρισμού εξαιρέσεων που χρησιμοποιεί το $@· σε νέο κώδικα προτιμήστε την try/catch για σαφέστερη εμβέλεια και χωρίς παγίδες του $@

  • $@ - παραμένει ανέγγιχτο από την try/catch· επιθεωρήστε την VAR αντί γι” αυτό