I/O · Ροή ελέγχου

die#

Εγείρει μια εξαίρεση.

Η die εκτοξεύει μια εξαίρεση φτιαγμένη από τη LIST. Αν η εξαίρεση συμβεί μέσα σε eval, η eval τερματίζει με undef και η $@ κρατά την τιμή της εξαίρεσης. Αν δεν την πιάσει κανείς, η Perl τυπώνει το μήνυμα στο STDERR και ο διερμηνέας εξέρχεται με μη μηδενική κατάσταση. Η εξαίρεση μπορεί να είναι απλή συμβολοσειρά, λίστα που μετατρέπεται σε συμβολοσειρά, ή αναφορά - τυπικά ένα blessed αντικείμενο που κουβαλά δομημένη κατάσταση σφάλματος.

Σύνοψη#

die LIST
die $message
die $exception_object
die                         # re-raise / propagate current $@

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

Η die δεν επιστρέφει. Ο έλεγχος μεταφέρεται στην πλησιέστερη δυναμικά περικλείουσα eval (η οποία τότε επιστρέφει undef σε βαθμωτό περιβάλλον ή την κενή λίστα σε περιβάλλον λίστας), ή - αν δεν υπάρχει περικλείουσα eval - ο διερμηνέας ξετυλίγεται, εκτελεί τους χειριστές END και DESTROY και εξέρχεται.

Η ίδια η τιμή της εξαίρεσης προσγειώνεται στην $@:

  • Συμβολοσειριακές εξαιρέσεις - το μετατραπέν σε συμβολοσειρά μήνυμα, συμπεριλαμβανομένου τυχόν προσαρτημένου at FILE line N.\n (βλ. παρακάτω).

  • Εξαιρέσεις με τιμή αναφοράς - η ίδια η αναφορά, αμετάβλητη. Αυτός είναι ο ιδιωματικός τρόπος εκτόξευσης ενός blessed αντικειμένου εξαίρεσης.

Σε μη πιασμένη έξοδο, ο κωδικός εξόδου παράγεται από τις $! και $?:

exit $! if $!;              # errno
exit $? >> 8 if $? >> 8;    # child exit status
exit 255;                   # last resort

Βασιστείτε μόνο στο ότι ο κωδικός εξόδου θα είναι μη μηδενικός· η ακριβής τιμή είναι μια κατά το δυνατόν βέλτιστη κωδικοποίηση όποιας καθολικής κατάστασης σφάλματος ήταν ενεργή τη στιγμή της εκτόξευσης.

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

  • $@ - εγγράφεται με την εξαίρεση κατά το ξετύλιγμα σε μια eval, διαβάζεται από τη μορφή της die χωρίς ορίσματα για τη διάδοση υπάρχουσας εξαίρεσης, και διαβάζεται από τον εκτυπωτή μη πιασμένων εξαιρέσεων.

  • $! - διαβάζεται κατά την παραγωγή κωδικού εξόδου για μη πιασμένη εξαίρεση, και συνηθίζεται να παρεμβάλλεται μέσα στο ίδιο το μήνυμα (die "open $f: $!").

  • $? - διαβάζεται κατά την παραγωγή κωδικού εξόδου αν η $! είναι μηδέν. Οι χειριστές END και DESTROY μπορούν ακόμη να τη μεταβάλουν πριν η διεργασία πραγματικά εξέλθει.

  • $. - ο τρέχων αριθμός γραμμής εισόδου, προσαρτάται σε συμβολοσειριακές εξαιρέσεις που στερούνται τελικού newline.

  • $SIG{__DIE__} - αν τεθεί, ο χειριστής εκτελείται πριν διαδοθεί η εξαίρεση, με την εξαίρεση ως όρισμά του. Ο χειριστής μπορεί να αντικαταστήσει την εξαίρεση καλώντας ξανά την die με διαφορετική τιμή.

  • $^S - αναγνώσιμη από τους χειριστές $SIG{__DIE__} ώστε να διακρίνουν αν η die συμβαίνει μέσα σε eval.

Ο κανόνας του τελικού newline#

Το αν η die προσαρτά πληροφορία τοποθεσίας εξαρτάται από έναν χαρακτήρα στο τέλος του μηνύματος:

  • Μήνυμα που τελειώνει σε "\n" - χρησιμοποιείται αυτούσιο. Δεν προσαρτάται τίποτα. Χρησιμοποιήστε αυτή τη μορφή όταν το μήνυμα είναι ήδη ένα πλήρες, προοριζόμενο για τον χρήστη διαγνωστικό.

  • Μήνυμα που δεν τελειώνει σε "\n" - η Perl προσαρτά " at FILE line N", και αν διαβάζεται κάποιο αρχείο, ", <HANDLE> line M", και στη συνέχεια τελική "." και newline. Χρησιμοποιήστε αυτή τη μορφή κατά την ανάπτυξη, ή όποτε ο εντοπισμός της κλήσης της die στον πηγαίο κώδικα είναι χρησιμότερος από ένα τακτοποιημένο μήνυμα.

die "bad config\n";                 # "bad config\n"
die "bad config";                   # "bad config at script.pl line 42.\n"

Ένα συνηθισμένο ιδίωμα είναι να προσαρτάται ", stopped" ώστε το επίθεμα τοποθεσίας να διαβάζεται φυσικά:

die "/etc/games is no good, stopped";
# /etc/games is no good, stopped at canasta line 123.

Στις εξαιρέσεις-αναφορές δεν προσαρτάται ποτέ πληροφορία τοποθεσίας - η μετατροπή ενός αντικειμένου σε συμβολοσειρά για επιθεώρηση θα ακύρωνε το νόημα της εκτόξευσης αντικειμένου. Αν θέλετε αρχείο και γραμμή μέσα σε μια δομημένη εξαίρεση, αποτυπώστε τα κατά τη στιγμή της κατασκευής (__FILE__, __LINE__, ή caller).

Εξαιρέσεις με τιμή αναφοράς#

Η διαβίβαση μιας αναφοράς - τυπικά ενός blessed αντικειμένου - επιτρέπει στην $@ να μεταφέρει δομημένη κατάσταση αντί για μια συμβολοσειρά που θα πρέπει να αναλύσετε εκ των υστέρων:

package MyApp::Error;
sub new   { my ($c, %a) = @_; bless { %a }, $c }
sub code  { $_[0]{code}  }
sub where { $_[0]{where} }

eval {
    die MyApp::Error->new(code => 'EPARSE', where => 'line 12');
};
if (my $err = $@) {
    if (ref($err) && $err->isa('MyApp::Error')) {
        warn "parse error at ", $err->where;
    }
    else {
        die $err;   # not ours - re-raise
    }
}

Υπερφορτώστε τη μετατροπή σε συμβολοσειρά στις κλάσεις εξαιρέσεων ώστε μια μη πιασμένη εξαίρεση να εξακολουθεί να τυπώνει χρήσιμο μήνυμα:

use overload '""' => sub { "[MyApp::Error ".$_[0]->code."]\n" };

Η μετατραπείσα σε συμβολοσειρά μορφή πρέπει να τελειώνει σε newline και να μην είναι κενή, σε αντιστοιχία με τη μεταχείριση των συμβολοσειριακών εξαιρέσεων.

Επειδή η $@ είναι καθολική, αντιγράψτε την σε μια λεκτική μεταβλητή πριν την επιθεωρήσετε - οποιαδήποτε κλήση μεθόδου, ref, ή isa εκτελέσετε κατά τον χειρισμό μπορεί η ίδια εσωτερικά να καλέσει eval και να αλλοιώσει την $@:

if (my $err = $@) { ... }       # safe
if ($@) { $@->method; ... }     # unsafe: method may reset $@

Διάδοση: die χωρίς όρισμα (ή με κενή συμβολοσειρά)#

Όταν η LIST είναι κενή ή μετατρέπεται σε συμβολοσειρά "", η die δεν εκτοξεύει νέα εξαίρεση - επανεγείρει ό,τι βρίσκεται στην $@:

  • Αν η $@ κρατά συμβολοσειρά, η die προσαρτά "\t...propagated at FILE line N.\n" και επανεκτοξεύει. Αυτός είναι ο καθιερωμένος τρόπος για να αφεθεί μια εξαίρεση να συνεχίσει στη στοίβα κλήσεων μετά από έναν έλεγχο μερικής αντιστοιχίας:

    eval { risky() };
    die unless $@ =~ /Expected exception/;
    
  • Αν η $@ κρατά αναφορά αντικειμένου με μέθοδο PROPAGATE, η μέθοδος αυτή καλείται ως $@ = eval { $@->PROPAGATE(__FILE__, __LINE__) }, και η τιμή επιστροφής αντικαθιστά την $@ πριν την επανεκτόξευση. Υλοποιήστε την PROPAGATE σε μια κλάση εξαίρεσης όταν θέλετε η εξαίρεση να καταγράφει την αλυσίδα των επανεγέρσεων.

  • Αν η $@ κρατά αναφορά αντικειμένου χωρίς PROPAGATE, η αναφορά επανεκτοξεύεται αμετάβλητη.

  • Αν η $@ είναι επίσης κενή, χρησιμοποιείται η συμβολοσειρά "Died".

Ο γάντζος $SIG{__DIE__}#

Θέτοντας την $SIG{__DIE__} εγκαθίσταται χειριστής που εκτελείται όταν πυροδοτείται η die, με την εξαίρεση ως όρισμά του. Ο χειριστής μπορεί να επιθεωρήσει ή να αντικαταστήσει την εξαίρεση καλώντας ξανά την die με διαφορετική τιμή. Εκτελείται ακόμη και μέσα σε eval, που είναι ο συνηθισμένος λόγος για τον οποίο τον θέλει κανείς εκτός εμποδίου:

local $SIG{__DIE__} = sub {
    die @_ if $^S;              # inside eval: do nothing special
    log_fatal(@_);              # outside eval: log before we exit
};

Η $^S είναι undef κατά τη μεταγλώττιση, αληθής μέσα σε eval, και ψευδής στο ανώτατο επίπεδο - χρησιμοποιήστε την για να φιλτράρετε εργασία του χειριστή που έχει νόημα μόνο για μη πιασμένες εξαιρέσεις.

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

Εγκατάλειψη με καθαρό μήνυμα (παρατηρήστε ότι το τελικό newline καταστέλλει την προσάρτηση αρχείου/γραμμής):

chdir '/var/spool' or die "can't cd to spool: $!\n";

Καλέστε την die χωρίς newline κατά την ανάπτυξη ώστε να προσαρτηθεί η τοποθεσία:

die "unexpected empty record";
# unexpected empty record at parse.pl line 87.

Πιάσιμο συμβολοσειριακής εξαίρεσης:

eval {
    parse($input);
};
if ($@) {
    warn "parse failed: $@";    # $@ already ends in "\n" if the
                                # die'd message did
}

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

eval {
    die MyApp::Error->new(code => 'EIO', detail => $!);
};
if (my $err = $@) {
    if (ref($err) && $err->isa('MyApp::Error')) {
        handle($err);
    }
    else {
        die $err;               # re-raise anything unexpected
    }
}

Υπό συνθήκη διάδοση - πιάστε μια κλάση, αφήστε τις υπόλοιπες να περάσουν:

eval { work() };
die unless $@ =~ /^recoverable:/;
recover();

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

  • Λίστα με δύο ή περισσότερα στοιχεία μετατρέπεται σε συμβολοσειρές και συνενώνεται για να σχηματίσει το μήνυμα: die "read failed on ", $file, ": $!". Ο κανόνας του newline ισχύει για το συνενωμένο αποτέλεσμα.

  • Κενή λίστα (die; ή die "";) πυροδοτεί τη διαδρομή διάδοσης που περιγράφηκε παραπάνω, όχι νέα εξαίρεση.

  • Αναφορά με τελικό newline μέσα στη μετατραπείσα σε συμβολοσειρά μορφή της είναι αδιάφορη: στην αναφορά δεν προσαρτάται ποτέ τοποθεσία, ανεξάρτητα από το τι παράγει η υπερφόρτωση "" της.

  • die μέσα σε DESTROY κατά την καθολική καταστροφή μπορεί ακόμη να πυροδοτήσει την $SIG{__DIE__} αλλά ενδέχεται να μη διαδοθεί όπως αναμένεται - ο διερμηνέας ήδη ξετυλίγεται. Κρατήστε τους καταστροφείς αμυντικούς.

  • Μη πιασμένη die κατά τη διάρκεια μπλοκ END εκτελεί τα υπόλοιπα μπλοκ END αλλά θέτει την κατάσταση εξόδου σύμφωνα με τον κανόνα $!/$? παραπάνω.

  • Εμφωλευμένη eval και $SIG{__DIE__}: ο χειριστής εκτελείται για κάθε die, συμπεριλαμβανομένων αυτών που πιάνονται από εσωτερική eval. Προστατευθείτε με τη $^S αν ο χειριστής έχει παρενέργειες.

  • Επανεκτόξευση της τρέχουσας $@: προτιμήστε γυμνό die; έναντι die $@;. Η γυμνή μορφή πυροδοτεί τη μηχανική διάδοσης (επίθεμα ...propagated, γάντζος PROPAGATE)· το die $@ όχι - μεταχειρίζεται την $@ ως νέα τιμή εξαίρεσης.

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

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

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

  • eval - η μόνη κατασκευή που πιάνει μια die· η μορφή της με μπλοκ παγιδεύει εξαιρέσεις στην $@

  • warn - ίδιοι κανόνες μορφοποίησης (τελικό newline καταστέλλει την τοποθεσία), αλλά γράφει στο STDERR και δεν ξετυλίγει

  • caller - αποτύπωση αρχείου και γραμμής τη στιγμή της εκτόξευσης κατά την κατασκευή δομημένου αντικειμένου εξαίρεσης

  • exit - χρησιμοποιήστε την όταν θέλετε συγκεκριμένο κωδικό εξόδου χωρίς τη μηχανική χειρισμού εξαιρέσεων

  • $@ - όπου προσγειώνεται η εξαίρεση αφού την πιάσει μια eval, και η πηγή από την οποία η die χωρίς ορίσματα επανεγείρει

  • $SIG{__DIE__} - γάντζος πριν την εκτόξευση που μπορεί να επιθεωρήσει ή να ξαναγράψει την εξαίρεση

  • $^S - λέει σε έναν χειριστή $SIG{__DIE__} αν εκτελείται μέσα σε eval