Πίνακες · Hashes

each#

Διάσχιση ενός πίνακα κατακερματισμού ή πίνακα μία εγγραφή τη φορά.

Η each προωθεί έναν επαναλήπτη ανά container και επιστρέφει την επόμενη εγγραφή. Για έναν πίνακα κατακερματισμού αυτή η εγγραφή είναι ένα ζεύγος (key, value)· για έναν πίνακα είναι ένα ζεύγος (index, value). Όταν ο επαναλήπτης έχει διασχίσει κάθε εγγραφή, η επόμενη κλήση επιστρέφει την κενή λίστα (ή undef σε βαθμωτό περιβάλλον) και έπειτα επανέρχεται στην αρχή, ώστε ένας νέος βρόχος while (each ...) να ξεκινήσει από την αρχή. Η σειρά του πίνακα κατακερματισμού είναι τυχαία ανά διεργασία και ανά πίνακα κατακερματισμού· η σειρά του πίνακα είναι αυστηρά από τον χαμηλότερο δείκτη προς τα πάνω.

Σύνοψη#

while (my ($k, $v) = each %h) { ... }
while (my ($i, $v) = each @a) { ... }
while (each %h) { ... }             # sets $_ to the key
my $k = each %h;                    # scalar context: key/index only

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

  • Περιβάλλον λίστας: μια λίστα δύο στοιχείων ($key, $value) για έναν πίνακα κατακερματισμού, ($index, $value) για έναν πίνακα. Σε εξάντληση, η κενή λίστα.

  • Βαθμωτό περιβάλλον: το κλειδί (για πίνακα κατακερματισμού) ή ο δείκτης (για πίνακα). Σε εξάντληση, undef.

  • Σκέτη each %h σε συνθήκη while/for: ελέγχει την οριστικότητα του επιστρεφόμενου κλειδιού/δείκτη, όχι την αληθοτιμή, και εκχωρεί το κλειδί στην $_. Αυτό κάνει το while (each %h) { print "$_\n" } να λειτουργεί ακόμη και όταν ένα κλειδί είναι η κενή συμβολοσειρά ή 0.

Μετά την εξάντληση ο επαναλήπτης επαναφέρεται σιωπηρά, οπότε η κλήση μετά από εκείνη που επέστρεψε κενή ξαναξεκινά την επανάληψη από την αρχή.

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

Κάθε πίνακας κατακερματισμού και κάθε πίνακας φέρει τον δικό του εσωτερικό επαναλήπτη. Οι each, keys και values προωθούν και μοιράζονται όλες αυτόν τον έναν επαναλήπτη - είναι τρεις όψεις του ίδιου δρομέα, όχι τρεις ανεξάρτητοι βρόχοι. Αυτό είναι το πιο σημαντικό μεμονωμένο γεγονός σχετικά με την each:

  • Η κλήση keys %h ή values %h (σε οποιοδήποτε περιβάλλον, ακόμη και ως εφάπαξ μέτρηση όπως scalar keys %h) επαναφέρει τον επαναλήπτη του πίνακα κατακερματισμού. Ένας βρόχος while (each %h) που διακόπτεται από scalar keys %h στο σώμα του θα ξαναξεκινήσει από την αρχή στην επόμενη επανάληψη - ή χειρότερα, θα εκτελείται για πάντα.

  • Η αναφορά ενός πίνακα κατακερματισμού σε περιβάλλον λίστας επαναφέρει επίσης τον επαναλήπτη του (π.χ. my @copy = %h, ή πέρασμα της %h σε υπορουτίνα). Οι επαναλήπτες πινάκων δεν επαναφέρονται από αναφορά σε περιβάλλον λίστας.

  • Δύο βρόχοι που επαναλαμβάνουν το ίδιο %h μοιράζονται έναν δρομέα. Η εμφώλευση while (each %h) { ... while (each %h) { ... } ... } επισκέπτεται κάθε εγγραφή το πολύ μία φορά συνολικά, όχι n * m φορές.

  • Ένας ανώνυμος πίνακας κατακερματισμού/πίνακας στη συνθήκη (each %{ +{ a => 1 } }) κατασκευάζει έναν νέο container σε κάθε επανάληψη, οπότε ο επαναλήπτης είναι πάντα φρέσκος - ο βρόχος δεν τερματίζει ποτέ.

  • Η σκέτη μορφή της each εκχωρεί στην $_· αν βασίζεστε στην $_ αλλού στο σώμα του βρόχου, αποθηκεύστε την με local.

Κάθε είσοδος σε ένα βρόχο while (each ...) λαμβάνει όποια θέση επαναλήπτη βρίσκεται ο container εκείνη τη στιγμή. Δεν υπάρχει τρόπος να απομονώσετε τον επαναλήπτη ενός βρόχου από άλλο κώδικα που αγγίζει τον ίδιο container. Αν το σώμα του βρόχου καλεί συνάρτηση που μπορεί να διαβάσει τον ίδιο πίνακα κατακερματισμού, το ασφαλές μοτίβο είναι αντί αυτού ένας βρόχος foreach πάνω σε keys.

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

Βασική επανάληψη πίνακα κατακερματισμού:

my %colour = (red => "#f00", green => "#0f0", blue => "#00f");
while (my ($name, $hex) = each %colour) {
    print "$name = $hex\n";
}
# order is unspecified

Επανάληψη πίνακα (Perl 5.12+):

my @letters = ('a' .. 'e');
while (my ($i, $c) = each @letters) {
    print "[$i] $c\n";
}
# [0] a
# [1] b
# [2] c
# [3] d
# [4] e

Εκτύπωση πίνακα κατακερματισμού σε ταξινομημένη σειρά - η each δεν ταξινομεί, οπότε καταφύγετε αντί αυτού σε keys συν sort:

for my $k (sort keys %colour) {
    print "$k = $colour{$k}\n";
}

Σκέτη each σε συνθήκη while, που θέτει την $_ στο κλειδί σε κάθε επανάληψη (Perl 5.18+):

while (each %ENV) {
    print "$_=$ENV{$_}\n";
}

Ασφαλής διαγραφή κατά την επανάληψη - μπορείτε να διαγράψετε το κλειδί που μόλις επιστράφηκε από την each χωρίς να ενοχλήσετε τον δρομέα:

while (my ($key, $value) = each %hash) {
    delete $hash{$key} if $value < 0;   # safe
}

Επανάληψη πίνακα κατακερματισμού με βρόχο foreach όταν οτιδήποτε στο σώμα μπορεί να αγγίξει το %hash (το εύρωστο μοτίβο - λάβετε πρώτα στιγμιότυπο των κλειδιών):

for my $key (keys %hash) {
    my $value = $hash{$key};
    # body is free to read %hash, call subs that read it, even
    # mutate it cautiously - our iteration list is fixed already.
}

foreach πολλαπλών τιμών πάνω σε πίνακα κατακερματισμού (Perl 5.36+), που καθιστά την each περιττή για τους περισσότερους βρόχους και αποφεύγει την παγίδα του κοινόχρηστου επαναλήπτη:

foreach my ($key, $value) (%hash) {
    print "$key => $value\n";
}

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

  • Ο επαναλήπτης δεν επαναφέρεται μεταξύ επανεισόδων: ένας βρόχος while (each %h) που εξέρχεται πρόωρα μέσω last, return ή die αφήνει τον επαναλήπτη στη μέση της διάσχισης. Ο επόμενος while (each %h) στον ίδιο πίνακα κατακερματισμού συνεχίζει από εκεί που σταμάτησε ο πρώτος, όχι από την αρχή. Καλέστε keys %h σε περιβάλλον κενού - keys %h; - για να εξαναγκάσετε επαναφορά πριν τον νέο βρόχο.

  • Οι keys/values επαναφέρουν τον επαναλήπτη: οποιαδήποτε κλήση στις keys ή values στον ίδιο πίνακα κατακερματισμού - συμπεριλαμβανομένης της scalar keys %h μέσα στο σώμα του βρόχου - επαναφέρει τον δρομέα.

  • Η αναφορά σε περιβάλλον λίστας επαναφέρει τον επαναλήπτη πίνακα κατακερματισμού, όχι πίνακα: το my @flat = %h επαναφέρει τον δρομέα του %h· το ισοδύναμο my @copy = @a δεν αγγίζει τον επαναλήπτη του @a.

  • Η διαγραφή κατά την επανάληψη δεν είναι καθορισμένη εκτός από την εγγραφή που επιστράφηκε πιο πρόσφατα. Η διαγραφή οποιουδήποτε άλλου κλειδιού μπορεί να οδηγήσει σε εγγραφές που επισκέπτονται δύο φορές ή παραλείπονται εντελώς.

  • Η προσθήκη κατά την επανάληψη δεν είναι καθορισμένη - η εισαγωγή νέου κλειδιού στη μέση του βρόχου μπορεί να επισκεφθεί ή να μην επισκεφθεί, και μπορεί να διαταράξει τη σειρά των εγγραφών που δεν έχουν ακόμη ιδωθεί.

  • Ανώνυμος container στη συνθήκη: η each %{ +{ a => 1 } } ή η each @{ [1,2,3] } κατασκευάζει έναν φρέσκο container κάθε φορά που αποτιμάται η συνθήκη, οπότε ο επαναλήπτης είναι πάντα νέος και ο βρόχος δεν τερματίζει ποτέ.

  • Δεσμευμένοι πίνακες κατακερματισμού και πίνακες εκχωρούν στις FIRSTKEY/NEXTKEY (πίνακες κατακερματισμού) ή FETCHSIZE/FETCH (πίνακες), οπότε η σειρά επανάληψης είναι ό,τι επιλέγει η δεσμευμένη κλάση και καμία από τις παραπάνω εγγυήσεις δεν ισχύει απαραίτητα.

  • Οριστικότητα έναντι αληθοτιμίας στη συνθήκη βρόχου: τα while (each %h) και while (my $k = each %h) ελέγχουν αμφότερα την οριστικότητα της έκφρασης, οπότε ένα κλειδί "0" ή "" δεν τερματίζει τον βρόχο. Αυτό αποτελεί ειδική περίπτωση συγκεκριμένα για την each.

  • Βαθμωτές εκφράσεις: η each $href σε βαθμωτό που κρατά αναφορά ήταν πειραματικό χαρακτηριστικό στην 5.14 και αφαιρέθηκε στην 5.24. Αποαναφέρετε ρητά: each %$href, each @$aref.

  • Κοινόχρηστη κατάσταση μεταξύ υπορουτινών: το πέρασμα του %h σε υπορουτίνα που καλεί each %h, keys %h ή values %h πάνω του διαταράσσει τον επαναλήπτη του καλούντος. Αν δημοσιεύετε έναν πίνακα κατακερματισμού, υποθέστε ότι οι καλούντες μπορεί να σπάσουν τον βρόχο σας· προτιμήστε foreach (keys ...) για ευρωστία.

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

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

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

  • keys - στιγμιότυπο όλων των κλειδιών (πίνακας κατακερματισμού) ή δεικτών (πίνακας)· επαναφέρει τον επαναλήπτη που χρησιμοποιεί η each

  • values - στιγμιότυπο όλων των τιμών· επαναφέρει τον επαναλήπτη που χρησιμοποιεί η each

  • delete - ασφαλής για την εγγραφή που μόλις επιστράφηκε από την each, μη ασφαλής για οποιαδήποτε άλλη κατά την επανάληψη

  • exists - έλεγχος ύπαρξης κλειδιού/δείκτη χωρίς διατάραξη του επαναλήπτη

  • for / foreach - ο πιο ασφαλής βρόχος όταν το σώμα μπορεί να αγγίξει τον container· συνδυάστε με keys για να λάβετε πρώτα στιγμιότυπο

  • sort - συνδυάστε με keys όταν χρειάζεστε καθορισμένη σειρά επανάληψης· η each δεν ταξινομεί ποτέ