# Hash με tie Ένα hash με tie είναι ο πλουσιότερος από τους τύπους tie, επειδή ένα hash κάνει περισσότερα από το να διαβάζει και να γράφει μεμονωμένα στοιχεία - επαναλαμβάνει, αναφέρει το μέγεθός του, ελέγχει την ύπαρξη κλειδιών, και καθαρίζει. Καθένα από αυτά είναι ένα ξεχωριστό hook. Τα hash ήταν ο πρώτος τύπος δεδομένων της Perl που μπορούσε να δεθεί με tie (η αρχική περίπτωση χρήσης ήταν το δέσιμο ενός `%hash` σε ένα αρχείο DBM στον δίσκο), και η διεπαφή ακόμη αντανακλά αυτή την κληρονομιά. Το πλήρες μενού μεθόδων βρίσκεται στη σελίδα αναφοράς του [`tie`](../../p5/core/perlfunc/tie.md). Αυτό το κεφάλαιο φτιάχνει μία κλάση και εξηγεί κάθε hook, με προσοχή στο μέρος που μπερδεύει τον κόσμο: το πρωτόκολλο επανάληψης. ## Μια πλήρης κλάση Ένα hash του οποίου τα κλειδιά είναι χωρίς διάκριση πεζών-κεφαλαίων - τα `$h{Name}` και `$h{NAME}` αναφέρονται στην ίδια θυρίδα: ```perl use v5.36; package CaseInsensitive { sub TIEHASH { my $class = shift; return bless {}, $class } sub STORE { my ($self, $key, $val) = @_; $self->{lc $key} = $val } sub FETCH { my ($self, $key) = @_; return $self->{lc $key} } sub EXISTS { my ($self, $key) = @_; return exists $self->{lc $key} } sub DELETE { my ($self, $key) = @_; return delete $self->{lc $key} } sub CLEAR { my $self = shift; %$self = () } sub FIRSTKEY { my $self = shift; my $reset = keys %$self; return each %$self } sub NEXTKEY { my $self = shift; return each %$self } sub SCALAR { my $self = shift; return scalar %$self } } tie my %h, 'CaseInsensitive'; $h{Name} = 'Ada'; $h{EMAIL} = 'ada@example.org'; say $h{name}; # Ada say $h{email}; # ada@example.org say exists $h{NAME} ? 'yes' : 'no'; # yes say scalar %h ? 'nonempty' : 'empty'; # nonempty for my $k (sort keys %h) { say "$k => $h{$k}"; } # email => ada@example.org # name => Ada ``` Το αντικείμενο είναι μια blessed αναφορά hash που χρησιμοποιείται ως ο πραγματικός αποθηκευτικός χώρος· τα hooks μετατρέπουν το κλειδί σε πεζά πριν το αγγίξουν. Παρατηρήστε ότι η επανάληψη επιστρέφει τα *αποθηκευμένα* (πεζά) κλειδιά, που είναι ακριβώς αυτό που πρέπει να κάνει ένα hash χωρίς διάκριση πεζών-κεφαλαίων. ## Το συμβόλαιο των μεθόδων `TIEHASH classname, LIST` : Ο κατασκευαστής. Επιστρέφει μια blessed αναφορά - συνήθως αλλά όχι κατ” ανάγκη μια αναφορά hash - που γίνεται το αντικείμενο με tie. `FETCH this, key` / `STORE this, key, value` : Ανάγνωση και εγγραφή ενός μόνο στοιχείου, το ίδιο ζεύγος με τα βαθμωτά αλλά με ένα όρισμα κλειδιού. Η τιμή επιστροφής του `STORE` αγνοείται. `EXISTS this, key` / `DELETE this, key` : Στηρίζουν τις ενσωματωμένες [`exists`](../../p5/core/perlfunc/exists.md) και [`delete`](../../p5/core/perlfunc/delete.md). Η τιμή επιστροφής του `DELETE` γίνεται η τιμή επιστροφής του `delete`· για να ταιριάζει με ένα απλό hash, επιστρέψτε ό,τι θα είχε επιστρέψει το `FETCH` για εκείνο το κλειδί πριν την αφαίρεσή του. `CLEAR this` : Πυροδοτείται όταν ολόκληρο το hash αδειάζει, τυπικά με την ανάθεση της κενής λίστας (`%h = ()`). Αφαιρέστε τα πάντα. `FIRSTKEY this` / `NEXTKEY this, lastkey` : Το πρωτόκολλο επανάληψης - δείτε παρακάτω. Μαζί οδηγούν τα [`keys`](../../p5/core/perlfunc/keys.md), [`values`](../../p5/core/perlfunc/values.md) και [`each`](../../p5/core/perlfunc/each.md). `SCALAR this` : Καλείται όταν το hash αποτιμάται σε βαθμωτό ή λογικό περιβάλλον (`scalar %h`, `if (%h)`, και από την 5.28 το `keys %h` σε λογικό περιβάλλον). Επιστρέψτε μια τιμή που είναι αληθής όταν το hash δεν είναι κενό και ψευδής όταν είναι κενό. `DESTROY this` και `UNTIE this` : Προαιρετικά hooks καθαρισμού, ταυτόσημα σε ρόλο με την περίπτωση του βαθμωτού. Το `UNTIE` καλύπτεται στην παγίδα του untie παρακάτω. ## Το πρωτόκολλο επανάληψης Αυτό είναι το μέρος της διεπαφής hash που δεν έχει ανάλογο στη διεπαφή του βαθμωτού, και το μέρος που πιο συχνά πάει στραβά. Όταν ξεκινά μια επανάληψη [`keys`](../../p5/core/perlfunc/keys.md), [`values`](../../p5/core/perlfunc/values.md) ή [`each`](../../p5/core/perlfunc/each.md), ο χρόνος εκτέλεσης καλεί το `FIRSTKEY` για να πάρει το πρώτο κλειδί, και έπειτα το `NEXTKEY` επανειλημμένα, περνώντας κάθε φορά το κλειδί που επιστράφηκε προηγουμένως, μέχρι μια μέθοδος να επιστρέψει την κενή λίστα ή `undef`. Και τα δύο καλούνται πάντα σε βαθμωτό περιβάλλον και πρέπει να επιστρέφουν απλώς ένα κλειδί· ο χρόνος εκτέλεσης καλεί ο ίδιος το `FETCH` για να πάρει κάθε τιμή. Δύο κανόνες κρατούν την επανάληψη σωστή: - **Το `FIRSTKEY` πρέπει να επαναφέρει κάθε εσωτερικό επαναλήπτη.** Όταν ο υποκείμενος αποθηκευτικός χώρος είναι ένα πραγματικό hash, αποτιμήστε πρώτα το `keys %$self` σε κενό ή βαθμωτό περιβάλλον - αυτό επαναφέρει τον δρομέα `each` της Perl ανά hash - και έπειτα καλέστε το `each`. Το αναλώσιμο `my $reset = keys %$self` στο παράδειγμα κάνει ακριβώς αυτό. Παραλείψτε το και ένα φρέσκο `keys %h` μπορεί να συνεχίσει από όπου σταμάτησε η τελευταία επανάληψη. - **Σηματοδοτήστε το τέλος με την κενή λίστα.** Όταν ο υποκείμενος αποθηκευτικός χώρος δεν είναι πραγματικό hash και δεν έχει δικό του `each`, επιστρέψτε την κενή λίστα (ή `undef`) μόλις παραδώσετε το τελευταίο κλειδί. ## Γιατί αξίζει να ορίσετε το `SCALAR` Χωρίς μια μέθοδο `SCALAR`, ο χρόνος εκτέλεσης μαντεύει την αλήθεια του hash σε λογικό περιβάλλον, και η εικασία μπορεί να είναι λανθασμένη - ιδίως, μπορεί να αναφέρει ένα hash ως μη κενό αμέσως μετά το άδειασμά του με επανειλημμένα `DELETE`. Αν το `if (%tied_hash)` έχει σημασία για τους καλούντές σας, ορίστε το `SCALAR` και επιστρέψτε την πραγματική απάντηση, όπως κάνει το παράδειγμα με το `scalar %$self`. ## Χρονισμός κλήσεων - Αναγνώσεις `$h{k}` → `FETCH`· `$h{k} = $v` → `STORE`. - `exists $h{k}` → `EXISTS`· `delete $h{k}` → `DELETE`. - `%h = ()` → `CLEAR`· `%h = (a => 1)` → `CLEAR` και μετά `STORE`. - `keys %h` / `values %h` / `each %h` → `FIRSTKEY` μία φορά, και μετά `NEXTKEY` ανά βήμα. Τα `keys` και `values` σε περιβάλλον λίστας καλούν επίσης `FETCH` για κάθε κλειδί. - `scalar %h`, `if (%h)` → `SCALAR` (αν είναι ορισμένο). - Μια φέτα hash `@h{qw(a b)}` καλεί το `FETCH` μία φορά ανά κλειδί· δεν υπάρχει hook για φέτες. ## Ελάχιστη βιώσιμη κλάση Ένα hash με tie ανάγνωσης/εγγραφής χρειάζεται τουλάχιστον τα `TIEHASH`, `FETCH` και `STORE`. Αν οι καλούντες πρόκειται ποτέ να το επαναλάβουν, προσθέστε τα `FIRSTKEY` και `NEXTKEY` - χωρίς αυτά, τα `keys` και `each` βλέπουν ένα κενό hash. Προσθέστε τα `EXISTS` και `DELETE` αν οι καλούντες χρησιμοποιούν εκείνες τις ενσωματωμένες· χωρίς αυτά, τα `exists`/`delete` πεθαίνουν στο σημείο χρήσης. Τα `SCALAR` και `CLEAR` ολοκληρώνουν την ορθότητα για λογικούς ελέγχους και μαζικό άδειασμα. ## Ο εύκολος τρόπος: κληρονομήστε από το `Tie::StdHash` Το `Tie::StdHash` (που συνοδεύει το `Tie::Hash`) υλοποιεί ολόκληρο το μενού πάνω σε μια blessed αναφορά hash. Κληρονομήστε από αυτό και υπερκαλύψτε μόνο τα hooks που πρέπει να συμπεριφέρονται διαφορετικά: ```perl package LoudHash { use Tie::Hash; our @ISA = ('Tie::StdHash'); sub STORE { my ($self, $k, $v) = @_; $self->{$k} = uc $v } } tie my %loud, 'LoudHash'; $loud{greeting} = 'hi'; say $loud{greeting}; # HI ``` Μόνο το `STORE` αλλάζει· τα `FETCH`, `EXISTS`, το πρωτόκολλο επανάληψης και ο κατασκευαστής προέρχονται όλα από τη βασική κλάση. Το `Tie::Hash` (ο γονέας) είναι η αφηρημένη εκδοχή που παρέχει ένα προεπιλεγμένο `TIEHASH` και `new` αλλά αφήνει σε εσάς να γράψετε τις μεθόδους προσπέλασης· το `Tie::StdHash` είναι η συγκεκριμένη που συνήθως θέλετε. ## Δείτε επίσης - [`tie`](../../p5/core/perlfunc/tie.md) - η ενσωματωμένη και το πλήρες μενού μεθόδων hash - [`tied`](../../p5/core/perlfunc/tied.md) - προσεγγίστε το αντικείμενο που στηρίζει για μεθόδους ειδικές της κλάσης - [`each`](../../p5/core/perlfunc/each.md) - ο επαναλήπτης που υλοποιούν τα `FIRSTKEY` / `NEXTKEY`· η δική του σελίδα τεκμηριώνει το συμβόλαιο τέλους επανάληψης - [`exists`](../../p5/core/perlfunc/exists.md) και [`delete`](../../p5/core/perlfunc/delete.md) - οι ενσωματωμένες πίσω από τα `EXISTS` και `DELETE` - [Βαθμωτά με tie](scalars.md) - η απλούστερη διεπαφή πάνω στην οποία βασίζεται αυτή - `Tie::Hash` - το άρθρωμα της βασικής κλάσης· το `Tie::StdHash` είναι η συγκεκριμένη εκδοχή