I/O

warn#

Εκπέμπει μια προειδοποίηση στο STDERR.

Η warn συμβολοσειροποιεί το LIST και τυπώνει το αποτέλεσμα στο STDERR - ο ίδιος μηχανισμός μορφοποίησης με τη die, μείον το ξετύλιγμα. Ο έλεγχος επιστρέφει στον καλούντα· τίποτα δεν εκπέμπεται, τίποτα δεν πιάνεται. Καταφύγετε σε αυτή όταν το πρόγραμμα πρέπει να συνεχίσει να εκτελείται αλλά ο χρήστης, ο διαχειριστής, ή το log αξίζει να ακούσει κάτι αναπάντεχο.

Σύνοψη#

warn LIST
warn $message
warn                         # re-surface current $@ as a warning

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

Η warn επιστρέφει 1 υπό κανονικές συνθήκες. Η τιμή επιστροφής σχεδόν ποτέ δεν είναι χρήσιμη - το νόημα της κλήσης είναι η παρενέργεια στο STDERR (ή σε ό,τι κάνει το $SIG{__WARN__} με το μήνυμα).

Σε αντίθεση με τη die, η warn δεν ξετυλίγει. Η εκτέλεση συνεχίζει με την εντολή μετά την κλήση.

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

  • $@ - διαβάζεται από τη μορφή χωρίς ορίσματα. Αν το $@ κρατά μη κενή τιμή, η warn την επανεμφανίζει (δείτε Διάδοση παρακάτω). Η warn δεν γράφει το $@.

  • $,, $\ - δεν χρησιμοποιούνται. Η warn δεν είναι print· οι διαχωριστές εξόδου και ο διαχωριστής εγγραφών δεν παίζουν κανέναν ρόλο. Το μήνυμα γράφεται ως μία μόνο συμβολοσειρά.

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

  • $SIG{__WARN__} - αν είναι ορισμένο, ο χειριστής εκτελείται αντί της εγγραφής στο STDERR. Δείτε Το hook $SIG{__WARN__} παρακάτω.

  • STDERR - ο προεπιλεγμένος προορισμός. Οποιαδήποτε ανακατεύθυνση του STDERR (στο επίπεδο κελύφους με 2>, open STDERR, ..., ή στρώμα PerlIO) επηρεάζει το πού προσγειώνεται η έξοδος της warn.

Ο κανόνας τελικής νέας γραμμής#

Ισχύει ο ίδιος κανόνας με τη die, και για τον ίδιο λόγο:

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

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

warn "cache is stale\n";            # "cache is stale\n"
warn "cache is stale";              # "cache is stale at main.pl line 42.\n"

Σε προειδοποιήσεις με τιμή αναφοράς δεν προσαρτάται ποτέ πληροφορία τοποθεσίας. Η συμβολοσειροποίηση ενός αντικειμένου για την προσθήκη αρχείου και γραμμής θα ακύρωνε το νόημα της μετάδοσής του.

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

Όταν το LIST είναι κενό ή συμβολοσειροποιείται σε "", η warn δεν εκπέμπει φρέσκο μήνυμα - επανεμφανίζει ό,τι βρίσκεται στο $@:

  • Αν το $@ είναι μη κενό, η warn προσαρτά "\t...caught" σε αυτό και εκπέμπει το αποτέλεσμα. Αυτός είναι ο κανονικός τρόπος να αντιληφθείτε ότι μια εξαίρεση πιάστηκε χωρίς να την αφήσετε να πεθάνει σιωπηρά:

    eval { risky() };
    warn if $@;                     # "<whatever died>\n\t...caught at ..."
    
  • Αν και το $@ είναι κενό, χρησιμοποιείται η συμβολοσειρά "Warning: Something's wrong".

Αυτό είναι σκόπιμα ασύμμετρο με τη die: η die χωρίς όρισμα ξανα-εκπέμπει (ενεργοποιώντας τον μηχανισμό διάδοσης και το hook PROPAGATE για αντικείμενα)· η warn χωρίς όρισμα αναφέρει ό,τι βρίσκεται ήδη στο $@.

Το hook $SIG{__WARN__}#

Ο ορισμός του $SIG{__WARN__} εγκαθιστά χειριστή που εκτελείται αντί της προεπιλεγμένης εγγραφής στο STDERR. Ο χειριστής λαμβάνει την εξαίρεση που προκύπτει από το LIST ως μοναδικό όρισμα και είναι υπεύθυνος για τη διάθεσή της - καταγραφή, επανεγγραφή, κλιμάκωση σε die, ή απόρριψη στο πάτωμα:

local $SIG{__WARN__} = sub {
    my ($msg) = @_;
    return if $msg =~ /^Use of uninitialized/;  # silently drop
    log_warning($msg);
};

Τρεις ασυμμετρίες με το $SIG{__DIE__} αξίζει να εμπεδωθούν:

  • Το προεπιλεγμένο μήνυμα καταστέλλεται. Το $SIG{__DIE__} εκτελείται παράλληλα με τον μηχανισμό εξαιρέσεων· το $SIG{__WARN__} εκτελείται αντί της προεπιλεγμένης εγγραφής στο STDERR. Αν ο χειριστής δεν κάνει τίποτα, η προειδοποίηση απορρίπτεται σιωπηρά.

  • Για να περάσετε διαπεραστικά την προειδοποίηση, καλέστε ξανά warn. Ο χειριστής δεν εισέρχεται ξανά για τη δική του κλήση warn, οπότε δεν υπάρχει άπειρος βρόχος:

    local $SIG{__WARN__} = sub {
        log_warning($_[0]);
        warn $_[0];                  # re-emit to STDERR as well
    };
    
  • Ένας χειριστής __WARN__ μπορεί να αποσιωπήσει υποχρεωτικές προειδοποιήσεις - προειδοποιήσεις που το no warnings δεν μπορεί να απενεργοποιήσει. Αυτό κάνει το $SIG{__WARN__} βαριά σφύρα· προτιμήστε no warnings '<category>' για στοχευμένη καταστολή και κρατήστε τον χειριστή για δρομολόγηση ή κλιμάκωση.

# wipe out *all* compile-time warnings, then switch on at runtime
BEGIN { $SIG{'__WARN__'} = sub { warn $_[0] if $DOWARN } }
my $foo = 10;
my $foo = 20;                       # duplicate-my silenced
$DOWARN = 1;
warn "\$foo is alive and $foo";     # now shows up

Η ενσωματωμένη warn έναντι του use warnings#

Αυτά είναι διαφορετικά πράγματα. Μη τα μπερδεύετε:

  • Η warn είναι ενσωματωμένη συνάρτηση που εκπέμπει ένα μήνυμα τώρα. Την καλείτε εσείς.

  • Το use warnings είναι pragma που ενεργοποιεί κατηγορίες διαγνωστικών μηνυμάτων κατά τη μεταγλώττιση και κατά τον χρόνο εκτέλεσης (μη αρχικοποιημένες τιμές, παρωχημένα χαρακτηριστικά, μη ανοιγμένα filehandles, και ούτω καθεξής). Ο μεταγλωττιστής και ο διερμηνέας εκπέμπουν αυτά τα διαγνωστικά εκ μέρους σας, χρησιμοποιώντας τον ίδιο μηχανισμό που χρησιμοποιεί η warn.

Τα διαγνωστικά της pragma ρέουν μέσα από το $SIG{__WARN__} ακριβώς όπως οι ρητές κλήσεις warn. Το no warnings '<category>' καταστέλλει τα διαγνωστικά της pragma στη λεξιλογική εμβέλειά του αλλά δεν έχει επίδραση σε ρητή warn που γράψατε εσείς - αυτή η κλήση πάντα πυροδοτείται.

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

Αναφορά ανακτήσιμου προβλήματος και συνέχιση της εκτέλεσης:

open my $fh, "<", $path
    or warn "skipping $path: $!\n" and next;

Διαγνωστικό λειτουργίας ανάπτυξης με προσαρτημένη τοποθεσία:

warn "unexpected record shape";
# unexpected record shape at parser.pl line 87.

Παρατήρηση μιας εξαίρεσης που πιάστηκε χωρίς να κατασταλεί:

eval { load_config() };
warn if $@;                         # surfaces "...caught at ..."

Δρομολόγηση κάθε προειδοποίησης μέσω ενός logger, με εκτύπωση και στο STDERR:

local $SIG{__WARN__} = sub {
    my ($msg) = @_;
    $logger->warn($msg);
    print STDERR $msg;              # preserve default visibility
};

Κλιμάκωση συγκεκριμένης προειδοποίησης σε μοιραίο σφάλμα:

local $SIG{__WARN__} = sub {
    die @_ if $_[0] =~ /corrupt database/;
    warn @_;                        # everything else: default path
};

Μετάδοση blessed αντικειμένου για δομημένες προειδοποιήσεις (ο παραλήπτης ενός hook $SIG{__WARN__} λαμβάνει την αναφορά, όχι συμβολοσειροποιημένη μορφή):

local $SIG{__WARN__} = sub {
    my ($w) = @_;
    if (ref($w) && $w->isa('MyApp::Warning')) {
        $logger->record($w);
    }
    else {
        print STDERR $w;
    }
};
warn MyApp::Warning->new(code => 'SLOW_IO', detail => $path);

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

  • Λίστα με δύο ή περισσότερα στοιχεία συμβολοσειροποιείται και συνενώνεται: warn "bad record ", $n, ": ", $raw. Ο κανόνας νέας γραμμής εφαρμόζεται στο συνενωμένο αποτέλεσμα.

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

  • Προειδοποίηση με τιμή αναφοράς μέσα σε χειριστή $SIG{__WARN__}: ο χειριστής λαμβάνει την αναφορά αμετάβλητη. Αν δεν είναι εγκατεστημένος χειριστής, η αναφορά συμβολοσειροποιείται στο STDERR μέσω της υπερφόρτωσης "" (ή της προεπιλογής της Perl MyClass=HASH(0x...)).

  • warn μέσα σε $SIG{__WARN__}: δεν εισέρχεται ξανά στον χειριστή. Η κλήση γράφει στο STDERR σαν να μην ήταν εγκατεστημένος χειριστής. Αυτό κάνει ασφαλή τον ιδιωματισμό «pass through».

  • warn κατά την καθολική καταστροφή: εξακολουθεί να λειτουργεί, αλλά το STDERR μπορεί ήδη να είναι κλειστό σε παθολογικές περιπτώσεις. Προειδοποιήσεις από χειριστές DESTROY που εκτελούνται κατά την έξοδο του διερμηνέα μπορεί να εξαφανιστούν.

  • STDERR κλειστό ή ανακατευθυνόμενο: η warn γράφει σε ό,τι δείχνει αυτή τη στιγμή το STDERR. Αν το STDERR είναι κλειστό, η εγγραφή αποτυγχάνει σιωπηρά· δεν εγείρεται σφάλμα, επειδή η ίδια η warn δεν ελέγχει.

  • Καμία σχέση με τα $\ / $,: η προσθήκη local $\ = "\n" δεν κάνει το warn "x" να τυπώσει νέα γραμμή. Ο κανόνας τελικής νέας γραμμής είναι ο μόνος μηχανισμός προσθήκης νέας γραμμής για την warn.

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

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

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

  • die - ίδιοι κανόνες μορφοποίησης (η τελική νέα γραμμή καταστέλλει την τοποθεσία, οι αναφορές περνούν αμετάβλητες), αλλά εγείρει εξαίρεση αντί να αναφέρει και να συνεχίσει

  • eval - συνδυάζεται με τη μορφή χωρίς ορίσματα της warn για τον ιδιωματισμό «πιάσε, εξέτασε, επανεμφάνισε»

  • $@ - η πηγή από την οποία αναφέρει η warn χωρίς όρισμα

  • $SIG{__WARN__} - το hook που αντικαθιστά την προεπιλεγμένη εγγραφή στο STDERR· χρησιμοποιήστε το για δρομολόγηση, φιλτράρισμα, ή κλιμάκωση

  • Carp - carp, cluck, croak, confess: προειδοποιήσεις και εξαιρέσεις που αναφέρουν από την οπτική του καλούντος και όχι του σημείου κλήσης, που είναι σχεδόν πάντα αυτό που θέλει μια βιβλιοθήκη