exists#
Έλεγχος εάν ένα στοιχείο πίνακα κατακερματισμού ή πίνακα, ή μια ονομασμένη υπορουτίνα, είναι παρόν - χωρίς να το δημιουργεί και χωρίς να ενδιαφέρεται για το τι κρατά.
Η exists θέτει ένα δομικό ερώτημα: υπάρχει εγγραφή σε αυτή τη θέση; Δεν ρωτά ποια είναι η τιμή της εγγραφής. Μια εγγραφή της οποίας η τιμή είναι undef εξακολουθεί να υπάρχει. Μια εγγραφή που δεν έχει εκχωρηθεί ποτέ δεν υπάρχει - η αναζήτησή της με απλή ανάγνωση θα επέστρεφε undef, αλλά η exists διακρίνει τις δύο περιπτώσεις.
Σύνοψη#
exists $hash{KEY}
exists $array[INDEX]
exists &subroutine
exists $ref->{A}{B} # autovivifies $ref->{A}!
Τι επιστρέφεται#
Μια λογική τιμή: 1 (αληθές βαθμωτό) αν το στοιχείο ή η υπορουτίνα είναι παρόν, η κενή συμβολοσειρά "" (ψευδές βαθμωτό) αν όχι. Το αποτέλεσμα είναι πάντα ένα απλό βαθμωτό - δεν υπάρχει παραλλαγή σε περιβάλλον λίστας.
my %h = (a => undef);
exists $h{a}; # 1 (key exists)
defined $h{a}; # "" (value is undef)
exists $h{b}; # "" (key does not exist)
Η exists δεν είναι η defined#
Οι δύο απαντούν σε διαφορετικά ερωτήματα και διαφωνούν ακριβώς όταν μια υπάρχουσα εγγραφή κρατά undef:
Κατάσταση |
| Απλή ανάγνωση | |
|---|---|---|---|
Δεν εκχωρήθηκε ποτέ | ψευδές | ψευδές | |
Εκχωρημένο σε | αληθές | ψευδές | |
Εκχωρημένο σε οποιαδήποτε άλλη τιμή | αληθές | αληθές | αυτή η τιμή |
Χρησιμοποιήστε την exists όταν χρειάζεται να γνωρίζετε αν ένα κλειδί έχει τοποθετηθεί στη δομή - π.χ. έναν πίνακα κατακερματισμού επιλογών όπου ένα σκέτο κλειδί σημαίνει «ο καλών δήλωσε συμμετοχή, η τιμή δεν έχει σημασία». Χρησιμοποιήστε την defined όταν χρειάζεται να γνωρίζετε αν μια τιμή είναι χρησιμοποιήσιμη.
Παραδείγματα#
Έλεγχος κλειδιού πίνακα κατακερματισμού. Κλασικό ιδίωμα πίνακα κατακερματισμού επιλογών - παρουσία, όχι αληθοτιμή:
sub configure {
my %opt = @_;
my $verbose = exists $opt{verbose}; # caller passed verbose => anything
my $color = $opt{color} // "auto"; # caller-supplied or default
...
}
Διάκριση μεταξύ «λείπει» και «παρόν αλλά undef»:
my %cache = (user_42 => undef); # cached: "we looked, nothing there"
if (exists $cache{user_42}) {
# hit - even though the value is undef, we already did the lookup
} else {
# miss - have to query the database
}
Έλεγχος αραιού πίνακα. Η διαγραφή ενός στοιχείου πίνακα αφήνει μια τρύπα που η exists αναφέρει ως ψευδή:
my @a = (10, 20, 30);
delete $a[1];
exists $a[0]; # 1
exists $a[1]; # "" (hole)
exists $a[2]; # 1
exists $a[99]; # "" (past the end)
Ύπαρξη υπορουτίνας. Αληθές μόλις η υπορουτίνα δηλωθεί, ακόμη και αν το σώμα είναι μια προδήλωση χωρίς ορισμό ακόμα:
sub later; # forward declaration
exists &later; # 1
defined &later; # "" (no body yet)
sub later { 42 }
defined &later; # 1
Εμφωλευμένη δομή - ο ασφαλής τρόπος. Ελέγξτε κάθε επίπεδο πριν την κάθοδο, επειδή η μορφή με αλυσίδα βελών έχει παρενέργεια (βλέπε Οριακές περιπτώσεις):
if (exists $tree{users}
&& exists $tree{users}{$id}
&& exists $tree{users}{$id}{email}) {
send_mail($tree{users}{$id}{email});
}
Οριακές περιπτώσεις#
Αυτο-δημιουργία ενδιάμεσων επιπέδων. Αυτή είναι η πιο σημαντική παγίδα. Η
exists $ref->{A}{B}{C}ελέγχει το πιο εσωτερικό κλειδί, αλλά η αποτίμηση της έκφρασης αυτο-δημιουργεί κάθε ενδιάμεσο πίνακα κατακερματισμού - οι$ref->{A}και$ref->{A}{B}εμφανίζονται ως κενοί πίνακες κατακερματισμού ακόμη και όταν ο έλεγχοςexistsεπιστρέφει ψευδές:my %h; exists $h{a}{b}{c}; # returns "" (false) exists $h{a}; # now returns 1 - $h{a} was created! exists $h{a}{b}; # likewise - now an empty hash
Το πιο εσωτερικό στοιχείο είναι το μόνο που δεν αυτο-δημιουργείται. Το ίδιο συμβαίνει μέσω αναφορών: η
exists $ref->{A}σε ένα undef$refαυτο-δημιουργεί την$refσε αναφορά πίνακα κατακερματισμού. Αν χρειάζεται να εξετάσετε μια βαθιά δομή χωρίς να την μεταλλάσσετε, διασχίστε την ένα επίπεδο τη φορά μεexistsσε κάθε βήμα, ή χρησιμοποιήστε ειδικό βοηθητικό όπως τη σημασιολογία [Data::Diver] (μια αλυσίδαeval/ εμβέλεια pragmano autovivification).Η
existsσε κλειδί με τιμήundefείναι αληθής. Αυτή είναι η καθοριστική διαφορά από τηνdefined. Ηdeleteαφαιρεί τόσο το κλειδί όσο και την τιμή· η εκχώρησηundefδιατηρεί το κλειδί.Όρια πίνακα. Η
exists $a[$i]είναι ψευδής όταν το$iείναι πέραν του τέλους του πίνακα ή όταν η θέση έχει διαγραφεί μεdeleteστη μέση του πίνακα. Οι αρνητικοί δείκτες μετρούν από το τέλος: ηexists $a[-1]ελέγχει το τελευταίο στοιχείο αν ο πίνακας είναι μη κενός.Η
existsσε πίνακα αποθαρρύνεται upstream. Η έννοια της διαγραφής ενός στοιχείου πίνακα δεν είναι εννοιολογικά καθαρή - ηdelete $a[1]αφήνει τρύπα αντί να μετατοπίζει. Ο περισσότερος κώδικας που καταφεύγει στηνexists $a[$i]εξυπηρετείται καλύτερα από έναν έλεγχο ορίων ($i <= $#a) ή με τη χρήση ενός πίνακα κατακερματισμού.Η
exists &sub()είναι συντακτικό σφάλμα. Το όρισμα πρέπει να ονοματίζει μια υπορουτίνα, όχι να καλεί μία. Ηexists &subρωτά «είναι δηλωμένη ηsub;»· ηexists &sub()θα σήμαινε «υπάρχει η τιμή επιστροφής της κλήσηςsub;», κάτι που είναι άνευ νοήματος.Η
AUTOLOADδεν μετρά. Ηexists &subείναι ψευδής για μια υπορουτίνα που θα δημιουργούνταν μέσωAUTOLOADστην πρώτη κλήση. Μια αποτυχημένηexistsσυνεπώς δεν εγγυάται ότι μια κλήση θα αποτύχει.Δεσμευμένες μεταβλητές. Για δεσμευμένους πίνακες κατακερματισμού και πίνακες, η
existsκαλεί τη μέθοδοEXISTSστο δεσμευμένο αντικείμενο. Η υλοποίηση tie αποφασίζει τι σημαίνει «ύπαρξη» - μια tieDBMελέγχει την εγγραφή στον δίσκο, μια οκνηρή tie μπορεί να υλοποιήσει την εγγραφή. Δείτε τοperltie.Το όρισμα πρέπει να είναι έκφραση lvalue της οποίας η τελική λειτουργία είναι αναζήτηση κλειδιού ή δείκτη, ή όνομα υπορουτίνας. Τα
exists func(),exists $scalar,exists @array,exists %hashείναι όλα σφάλματα. Γίνονται δεκτά μόνο η πρόσβαση σε στοιχείο και το&sub.
Διαφορές από το upstream#
Πλήρως συμβατό με το upstream Perl 5.42.
Δείτε επίσης#
defined- ρωτά αν η τιμή είναι χρησιμοποιήσιμη, όχι αν το κλειδί είναι παρόν· διαφέρει από τηνexistsμόνο όταν η αποθηκευμένη τιμή είναιundefdelete- αφαιρεί μια εγγραφή ώστε ηexistsσε αυτή να γίνει ψευδής· το αντίστοιχο τηςexistseach- επαναλαμβάνει ζεύγη κλειδιού/τιμής ενός πίνακα κατακερματισμού· επισκέπτεται μόνο κλειδιά για τα οποία ηexistsείναι αληθήςkeys- επιστρέφει τη λίστα των υπαρχόντων κλειδιών· ηexists $h{$k}ισοδυναμεί με το ερώτημα αν το$kείναι μεταξύ τωνkeys %h, αλλά O(1) αντί για O(n)ref- κατηγοριοποιεί σε τι δείχνει μια αναφορά· χρήσιμη πριν τηνexistsσε$ref->{...}αν δεν είστε σίγουροι ότι η$refείναι αναφορά πίνακα κατακερματισμούscalar- εξαναγκασμός βαθμωτού περιβάλλοντος· σημειώστε ότι ηexistsείναι ήδη μόνο βαθμωτή και δεν τη χρειάζεται