Εμβέλεια: my, our, local, state#
Μέσα σε μια sub, τέσσεροι δηλωτές ελέγχουν πού ζει μια μεταβλητή, πόσο ζει, και ποιος μπορεί να τη δει. Διαλέξτε λάθος και η sub διαρρέει κατάσταση, αποτυγχάνει να αποτυπώσει σωστά σε closure, ή σιωπηρά αλλοιώνει κάτι στο οποίο βασιζόταν ο καλών.
Δηλωτής | Πεδίο | Διάρκεια ζωής | Τυπική χρήση |
|---|---|---|---|
| λεξιλογική (το μπλοκ) | μέχρι να τελειώσει το μπλοκ | η προεπιλογή· ιδιωτικές τοπικές |
| λεξιλογικό ψευδώνυμο προς πακέτο | όσο υπάρχει το πακέτο | κοινόχρηστες καθολικές πακέτου με σύντομο όνομα |
| δυναμική (το δέντρο κλήσεων) | μέχρι να τελειώσει το μπλοκ | προσωρινή αλλαγή ειδικής μεταβλητής |
| λεξιλογική (το μπλοκ) | διάρκεια ζωής προγράμματος | επίμονη κατάσταση ανά sub, αρχικοποίηση μία φορά |
my - λεξιλογικές τοπικές#
Η my είναι ο καθημερινός δηλωτής:
sub greet {
my ($name) = @_;
my $message = "Hello, $name!";
return $message;
}
Οι μεταβλητές υπάρχουν για τη διάρκεια της κλήσης, είναι ιδιωτικές στο σώμα, και αποθηκεύονται στο pad της sub (μία υποδοχή ανά δηλωμένη λεξιλογική). Δεν είναι ορατές στους καλούντες, τους κληθέντες, ή κώδικα μέσω eval που δεν βρίσκεται κειμενικά ένθετος μέσα στη sub.
Οι μεταβλητές my είναι οι μόνες που αποτυπώνονται σωστά σε closures. Τα closures αποτυπώνουν κελιά στο περιβάλλον pad, και μόνο οι μεταβλητές my (και state) αποκτούν κελιά pad.
our - καθολικές πακέτου με λεξιλογικό ψευδώνυμο#
package Counter;
sub increment {
our $value; # alias to $Counter::value
$value++;
return $value;
}
Η our $x δηλώνει ένα λεξιλογικό ψευδώνυμο στην τρέχουσα εμβέλεια προς τη μεταβλητή πακέτου $Pkg::x. Η ίδια η μεταβλητή είναι καθολική. Αν δύο πακέτα δηλώσουν our το $VERSION, καθένα παίρνει τη δική του - η our προσθέτει ως πρόθεμα το τρέχον όνομα πακέτου.
Χρησιμοποιήστε our όταν:
Θέλετε πραγματικά μια κοινόχρηστη μεταβλητή σε επίπεδο πακέτου.
Θέλετε να αποσιωπήσετε τις διαμαρτυρίες
use strict 'vars';για μεταβλητή που πρέπει να είναι καθολική πακέτου ($VERSION,@ISA,@EXPORT, ψευδώνυμα%ENV, …).
Μη χρησιμοποιείτε our για να μοιραστείτε κατάσταση μεταξύ subs στο ίδιο αρχείο. Γι” αυτό χρησιμεύει η my σε εμβέλεια αρχείου:
package Counter;
my $value = 0; # private to this package's file
sub increment { ++$value }
sub get { $value }
local - δυναμικά οριοθετημένο προσωρινό#
Η local δεν δηλώνει νέα μεταβλητή. Αποθηκεύει την τρέχουσα τιμή μιας υπάρχουσας (συνήθως καθολικής) μεταβλητής, θέτει νέα τιμή, και επαναφέρει την παλιά τιμή όταν εξέλθει το περικλείον μπλοκ - ακόμα και σε εξαίρεση:
sub slurp {
my ($path) = @_;
open my $fh, '<', $path or die "open $path: $!";
local $/; # slurp mode for this sub only
return <$fh>;
}
Χωρίς τη local, η $/ του καλούντος θα αλλοιωνόταν μόνιμα. Με αυτή, η αλλαγή περιορίζεται στη δυναμική έκταση της slurp - συμπεριλαμβανομένων οποιωνδήποτε subs η slurp τυχαίνει να καλέσει.
Η local είναι το σωστό εργαλείο για σχεδόν κάθε παράκαμψη ειδικής μεταβλητής ($/, $\, $,, $_, $@, χειριστές σημάτων στο %SIG). Σπάνια είναι το σωστό εργαλείο για συνηθισμένες μεταβλητές χρήστη - εκείνες χρειάζονται my.
Για πλήρη κατάλογο, δείτε local και τις σελίδες μεταβλητών κατάσταση σφάλματος και I/O, που αναφέρουν ποιες ειδικές χρειάζονται local και σε ποια μοτίβα.
state - αρχικοποίηση μία φορά, διατήρηση για πάντα#
use feature 'state';
sub counter {
state $n = 0; # initialised once, ever
return ++$n;
}
counter(); # 1
counter(); # 2
counter(); # 3
Οι μεταβλητές state είναι λεξιλογικές που επιβιώνουν μεταξύ κλήσεων. Ο αρχικοποιητής εκτελείται την πρώτη φορά που ο έλεγχος φτάνει στη δήλωση· οι επόμενες κλήσεις τον παραλείπουν.
Η state είναι το σωστό εργαλείο για:
Caches και μετρητές ανά sub όπου το κόστος κατασκευής δεδομένων κυριαρχεί και δεν θέλετε εργοστάσιο closures.
Εφάπαξ ρύθμιση που εξαρτάται από τιμές μη διαθέσιμες κατά τη μεταγλώττιση:
sub compiled_re { my ($pattern) = @_; state %cache; $cache{$pattern} //= qr/$pattern/; return $cache{$pattern}; }
(Σημείωση: αυτό αποθηκεύει μόνο το πρώτο μοτίβο με κυριολεκτικό
stateενός μόνο regex· η μορφή hash το γενικεύει.)
Closures: αποτύπωση περιβάλλουσας my#
Μια ανώνυμη sub αποτυπώνει κάθε μεταβλητή my (ή state) από την περιβάλλουσα εμβέλεια στην οποία αναφέρεται κειμενικά:
sub make_adder {
my ($n) = @_;
return sub {
my ($x) = @_;
return $x + $n; # captures $n
};
}
my $add5 = make_adder(5);
my $add9 = make_adder(9);
$add5->(3); # 8
$add9->(3); # 12
Κάθε κλήση στη make_adder δημιουργεί ένα νέο $n, και το επιστρεφόμενο closure αναφέρεται στο δικό του $n. Δύο κλήσεις παράγουν δύο ανεξάρτητους μετρητές / αθροιστές / μηχανές κατάστασης.
Η έκπληξη του closure-πάνω-σε-μεταβλητή-βρόχου#
my @subs;
for my $i (1, 2, 3) {
push @subs, sub { $i };
}
print $_->(), "\n" for @subs;
# 1
# 2
# 3 - fresh $i each iteration: each closure sees its own
Αυτή είναι η σωστή συμπεριφορά με for my $i: κάθε επανάληψη δηλώνει ένα νέο $i, κάθε closure αποτυπώνει το δικό του.
Η σφαλμένη μορφή εμφανίζεται όταν η $i δηλώνεται έξω από τον βρόχο:
my $i;
my @subs;
for $i (1, 2, 3) { # NO `my` - same $i every iteration
push @subs, sub { $i };
}
print $_->(), "\n" for @subs;
# 3
# 3
# 3 - all three closures share the one $i, and its final value is 3
Δηλώνετε πάντα τις μεταβλητές βρόχου με my. Η αποτύπωση closure ακολουθεί τη μεταβλητή, όχι την τιμή, και «ίδια μεταβλητή» έναντι «διαφορετική μεταβλητή» αποφασίζεται στη θέση my.
Αποτύπωση our και καθολικών πακέτου#
Τα ψευδώνυμα our ζουν για ολόκληρο το πακέτο, οπότε ένα closure που αποτυπώνει τη $Counter::value μοιράζεται κατάσταση με κάθε άλλο κομμάτι κώδικα που αγγίζει τη $Counter::value. Αυτό σχεδόν πάντα δεν είναι αυτό που θέλετε - closures πάνω σε καθολικές πακέτου σημαίνουν ότι η σχεδίαση χρειάζεται my.
Διάρκεια ζωής pad#
Κάθε ενεργή κλήση sub έχει ένα pad, μία υποδοχή ανά δηλωμένη λεξιλογική. Το pad είναι αυτό στο οποίο γράφει η my και αυτό στο οποίο τα closures κρατούν αναφορά. Όσο ένα closure είναι ζωντανό, κάθε pad που αποτυπώνει είναι ζωντανό - ακόμα κι αν η αρχική κλήση έχει πολύ καιρό επιστρέψει. Έτσι η $n της make_adder επιβιώνει μετά την κλήση στην ίδια τη make_adder.
Δείτε επίσης#
my,our,local,state- σελίδες λεπτομερειών perlfunc για κάθε δηλωτή.@_- η μία μεταβλητή που πάντα υπάρχει σε μια sub ανεξάρτητα από δηλωτές.Δήλωση - ανώνυμες subs και η λεξιλογική μορφή
my sub.Αναδρομή - trampolines βασισμένα σε closures και
__SUB__.Ειδικές μεταβλητές - σχεδόν κάθε ειδική χρειάζεται
local, όχιmy.