Εμβέλεια

local#

Αποθηκεύει την τρέχουσα τιμή μιας μεταβλητής πακέτου και την επαναφέρει όταν η περικλείουσα εμβέλεια τερματίζεται.

Η local είναι ο τελεστής δυναμικής εμβέλειας. Δεν δηλώνει νέα μεταβλητή - απλώνεται σε μια υπάρχουσα μεταβλητή πακέτου (καθολική), αποθηκεύει την τρέχουσα τιμή σε μια κρυφή στοίβα διάσωσης και κανονίζει η αρχική τιμή να επαναφερθεί όταν ο έλεγχος εγκαταλείπει το τρέχον μπλοκ, την eval ή το do FILE. Οι καλούμενες υπορουτίνες βλέπουν την προσωρινή τιμή. Για τις περισσότερες ανάγκες τύπου «θέλω μια μεταβλητή τοπική σε αυτό το μπλοκ», το σωστό εργαλείο είναι η my· καταφύγετε στην local συγκεκριμένα όταν η μεταβλητή πρέπει να είναι καθολική σε επίπεδο πακέτου - οι μεταβλητές στίξης, τα filehandles ή εγγραφές στον πίνακα συμβόλων - και θέλετε αυτή η καθολική να έχει διαφορετική τιμή για τη διάρκεια ενός μπλοκ και κάθε υπορουτίνας που αυτό καλεί.

Σύνοψη#

local EXPR
local $var
local $var = EXPR
local (@list) = LIST
local $hash{key}
local $array[i]
local *GLOB

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

Την τιμή της τοπικοποιημένης έκφρασης (τη νέα τιμή, μετά από οποιαδήποτε εκχώρηση στην ίδια εντολή). Η παρακολούθηση της στοίβας διάσωσης είναι παρενέργεια· η τιμή επιστροφής έχει σημασία μόνο όταν η local εμφανίζεται μέσα σε μεγαλύτερη έκφραση:

our $x = 2;
foo($x, local $x = $x + 1, $x);   # foo() receives (2, 3, 3)

Δυναμική εμβέλεια, όχι λεξιλογική εμβέλεια#

Η local και η my είναι διαφορετικά είδη εμβέλειας:

  • Η my δημιουργεί μια νέα, λεξιλογικά οριοθετημένη μεταβλητή. Μόνο κώδικας κειμενικά μέσα στο περικλείον μπλοκ μπορεί να τη δει. Οι καλούμενες υπορουτίνες όχι.

  • Η local δεν δημιουργεί τίποτα. Παρακάμπτει προσωρινά την τιμή μιας υπάρχουσας μεταβλητής πακέτου. Κάθε κομμάτι κώδικα - αυτό το μπλοκ και κάθε υπορουτίνα που καλεί, άμεσα ή μεταβατικά - βλέπει τη νέα τιμή μέχρι να τερματιστεί η εμβέλεια.

Γι” αυτόν τον λόγο η local είναι το σωστό εργαλείο για μεταβλητές στίξης όπως οι $/, $\, $,, $_ και $@: πρόκειται για καθολικές μεταβλητές πακέτου που η Perl runtime (και ό,τι καλείται από τον κώδικά σας) διαβάζει με γνωστά ονόματα. Μια επικάλυψη με my δεν θα τις επηρέαζε.

sub slurp {
    my ($path) = @_;
    open my $fh, "<", $path or die "open $path: $!";
    local $/;                     # undef $/ for this sub only
    return <$fh>;                 # read to EOF in one go
}

Η γραμμή local $/ πιο πάνω είναι το πιο κοινό ιδίωμα local στον πραγματικό κώδικα: αναιρεί προσωρινά τον διαχωριστή εγγραφών εισόδου ώστε η readline (<$fh>) να επιστρέψει ολόκληρο το αρχείο. Όταν η slurp επιστρέφει, η $/ επαναφέρεται σε ό,τι ήταν πριν - ακόμη και αν ο καλών την είχε επίσης αλλάξει.

Τι μπορείτε και τι δεν μπορείτε να τοπικοποιήσετε#

Μπορείτε να εφαρμόσετε local σε:

  • Βαθμωτά, πίνακες, hashes πακέτου - local $Pkg::var, local @Pkg::arr, local %Pkg::hash. Το bareword local $var στοχεύει τη μεταβλητή στο τρέχον πακέτο.

  • Ήδη δηλωμένες μεταβλητές our - η our δημιουργεί λεξιλογικό ψευδώνυμο προς μια μεταβλητή πακέτου, οπότε η local πάνω της τοπικοποιεί την υποκείμενη καθολική.

  • Μεμονωμένα στοιχεία και slices πινάκων/hashes πακέτου - local $hash{key}, local $array[3], local @hash{qw(a b)}, local @array[0..2].

  • Globs - η local *name δημιουργεί μια καινούργια εγγραφή στον πίνακα συμβόλων, έτσι ώστε οι $name, @name, %name, &name και το filehandle name να επαναφέρονται δυναμικά όλα μαζί.

  • Υπό συνθήκη lvalues - local ($cond ? $v1 : $v2) όταν η επιλεγμένη διακλάδωση είναι η ίδια τοπικοποιήσιμη.

Δεν μπορείτε να εφαρμόσετε local σε:

  • Μια μεταβλητή my. Οι μεταβλητές my είναι λεξιλογικές που ζουν σε pad, όχι στον πίνακα συμβόλων· δεν έχουν όνομα πακέτου ώστε η local να τις αποθηκεύσει κάτω από αυτό. Η προσπάθεια αποτελεί σφάλμα κατά τη μεταγλώττιση: Can't localize lexical variable $x.

  • Μια μεταβλητή state. Για τον ίδιο λόγο.

  • Μόνο-για-ανάγνωση μαγικές καθολικές. Το local $1 = 2 αποτυγχάνει με Modification of a read-only value attempted - οι μεταβλητές σύλληψης δεν μπορούν να δεχθούν εκχώρηση. (Η μία εξαίρεση είναι η $_: η local $_, από την 5.14, ρητά αφαιρεί τη μαγεία ώστε να μπορεί να επαναχρησιμοποιηθεί με ασφάλεια σε υπορουτίνα.)

Τοπικοποίηση στοιχείων σύνθετων τύπων#

Τα local $hash{key} και local $array[i] αποθηκεύουν τη συγκεκριμένη θέση, όχι την τιμή που τυχαίνει να βρίσκεται εκεί. Όταν η εμβέλεια τερματίζεται, η αρχική τιμή επαναφέρεται σε εκείνη ακριβώς τη θέση - ακόμη και αν το στοιχείο διαγράφηκε ή ο πίνακας κοντύνε στο μεταξύ. Ένα διαγραμμένο κλειδί hash επαναεμφανίζεται· ένα στοιχείο πίνακα που έγινε pop επανεμφανίζεται, γεμίζοντας τον πίνακα με undef αν χρειάζεται.

our %hash = (a => "is");
{
    local $hash{a} = "drill";
    delete $hash{a};              # gone for now...
}
print $hash{a}, "\n";             # ...but restored to "is"

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

Βασικά: δώστε σε μια καθολική μια προσωρινή τιμή για ένα μπλοκ. Οι υπορουτίνες που καλούνται μέσα από το μπλοκ βλέπουν τη νέα τιμή.

our $verbose = 0;
sub log_msg { print "[v=$verbose] $_[0]\n" }

{
    local $verbose = 1;
    log_msg("inside");            # prints "[v=1] inside"
}
log_msg("outside");               # prints "[v=0] outside"

Ιδίωμα slurp-αρχείου με $/:

my $content = do {
    open my $fh, "<", $path or die "open $path: $!";
    local $/;                     # list context for <> now reads all
    <$fh>;
};

Παγιδεύστε προσωρινά την $@ ώστε μια εσωτερική eval να μην επικαλύψει το εκκρεμές σφάλμα του καλούντος:

sub try_cleanup {
    local $@;                     # caller's $@ preserved
    eval { risky_cleanup() };
    # even if eval failed, caller's $@ is untouched
}

Προεπιλογές print σε στιλ Python, οριοθετημένες σε ένα μπλοκ:

{
    local $, = " ";
    local $\ = "\n";
    print 1, 2, 3;                # "1 2 3\n"
}
print 1, 2, 3;                    # "123" - defaults restored

Η μορφή λίστας χρειάζεται παρενθέσεις. Οι παρενθέσεις δίνουν επίσης στη δεξιά πλευρά περιβάλλον λίστας - ακριβώς όπως και η my:

our (@wid, %get);
local (@wid, %get) = (@defaults, %overrides);

Τοπικοποιήστε ένα μεμονωμένο στοιχείο hash - χρήσιμο για να περάσετε παρακάμψεις μέσα από μια κλήση χωρίς να αγγίξετε άσχετα κλειδιά:

our %config = (timeout => 30, retries => 3);
{
    local $config{timeout} = 5;
    do_probe();                   # sees timeout => 5
}
# %config back to (timeout => 30, retries => 3)

Τοπικοποίηση glob - ολόκληρη η εγγραφή στον πίνακα συμβόλων για το LOG αντικαθίσταται:

{
    local *LOG;
    open LOG, ">", "/tmp/trace.$$" or die $!;
    run_traced();                 # sees our private LOG filehandle
}
# original LOG (if any) is back

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

  • Τελεστής χρόνου εκτέλεσης, όχι δήλωση. Η local εκτελείται κάθε φορά που ο έλεγχος φτάνει σε αυτήν. Μέσα σε βρόχο αποθηκεύει και επαναφέρει σε κάθε επανάληψη - μετρήσιμη επιβάρυνση. Βγάλτε την έξω από τον βρόχο όταν η πρόθεση είναι «για ολόκληρο τον βρόχο»:

    { local $/ = "\n\n";            # once, not per iteration
        while (<$fh>) { ... }
    }
    
  • Η εκχώρηση αποτιμάται πριν από την αποθήκευση. Η δεξιά πλευρά εκτελείται στην περικλείουσα δυναμική εμβέλεια, οπότε η local $x = $x + 1 διαβάζει την παλιά $x, μετά αποθηκεύει, και κατόπιν εκχωρεί τη νέα τιμή.

  • Το όριο εμβέλειας είναι δυναμικό, όχι λεξιλογικό. Η αποθήκευση αναιρείται όταν το τρέχον μπλοκ εξέρχεται σε χρόνο εκτέλεσης, όχι όταν το πηγαίο μπλοκ τερματίζεται κειμενικά. Η έξοδος μέσω return, die, last, next ή μη-τοπικού goto εξακολουθεί να ενεργοποιεί την επαναφορά.

  • Η local σε μια my είναι σφάλμα κατά τη μεταγλώττιση. Ο αναλυτής απορρίπτει το my $x; local $x; με Can't localize lexical variable $x. Χρησιμοποιήστε our (ή πλήρως προσδιορισμένο όνομα) αν πραγματικά χρειάζεστε δυναμική εμβέλεια σε εκείνο το όνομα.

  • Πίνακες και hashes με tie δεν συμπεριφέρονται προς το παρόν όπως περιγράφει το POD - η τοπικοποίηση ολόκληρου του συσσωματώματος είναι ελαττωματική στο upstream. Η τοπικοποίηση μεμονωμένων στοιχείων ενός συσσωματώματος με tie είναι ασφαλής. Αυτή η επιφύλαξη κληρονομείται από την upstream Perl.

  • Στις μόνο-για-ανάγνωση μαγικές δεν μπορεί να γίνει εκχώρηση. Το local $1 = "x" πεθαίνει σε χρόνο εκτέλεσης. Μπορείτε να κάνετε local $_ (η μαγεία αφαιρείται από την 5.14) αλλά όχι local $1, local $&, κ.λπ.

  • Αρνητικοί δείκτες πίνακα στο local $array[-1] τεκμηριώνονται ως «ιδιαίτερα εκπληκτικοί» στο upstream· αντιμετωπίστε τη συμπεριφορά ως ασταθή και αποφύγετέ την.

  • Το delete local επεκτείνει την local στην αφαίρεση στοιχείου: το delete local $hash{key} διαγράφει την εγγραφή για το τρέχον μπλοκ και την επαναφέρει κατά την έξοδο. Επιστρέφει την τιμή που υπήρχε πριν από την τοπικοποίηση.

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

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

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

  • my - λεξιλογική (κατά τη μεταγλώττιση, με εμβέλεια μπλοκ) δήλωση· το σωστό εργαλείο όταν θέλετε μια πραγματικά ιδιωτική μεταβλητή

  • our - λεξιλογικό ψευδώνυμο προς μια μεταβλητή πακέτου· συνηθισμένος εταίρος της local όταν η καθολική βρίσκεται σε άλλο πακέτο

  • state - επίμονη λεξιλογική· δεν μπορεί να τοπικοποιηθεί με local

  • delete - σε συνδυασμό με την local (delete local $h{k}) για να περιορίσει τη διαγραφή στοιχείου στο τρέχον μπλοκ

  • eval - συνηθισμένος στόχος της local: η local $@ γύρω από εσωτερική eval αποτρέπει τη διαρροή σφαλμάτων προς τον καλούντα

  • $/ - διαχωριστής εγγραφών εισόδου· καθιερωμένος στόχος της local για αναγνώσεις αρχείων σε λειτουργία slurp

  • $_ - προεπιλεγμένο βαθμωτό· η local $_ αφαιρεί τη μαγεία (από την 5.14) ώστε μια υπορουτίνα να μπορεί να την επαναχρησιμοποιήσει με ασφάλεια

  • $@ - τελευταίο σφάλμα eval· η local $@ θωρακίζει τον καλούντα από το σφάλμα μιας εσωτερικής eval