# האשים קשורים האש קשור הוא העשיר ביותר מבין סוגי ה־tie, מכיוון שהאש עושה יותר מאשר קריאה וכתיבה של אלמנטים בודדים - הוא מבצע איטרציה, מדווח על גודלו, בודק קיום של מפתח, ומתרוקן. כל אחד מאלה הוא הוו נפרד. האשים היו סוג הנתונים הראשון ב־Perl שנקשר (מקרה השימוש המקורי היה קישור של `%hash` לקובץ DBM על הדיסק), והממשק עדיין משקף מורשת זו. תפריט המתודות המלא נמצא בעמוד הייחוס של [`tie`](../../p5/core/perlfunc/tie.md). פרק זה בונה מחלקה אחת ומסביר כל הוו, עם תשומת לב לחלק שמכשיל אנשים: פרוטוקול האיטרציה. ## מחלקה שלמה האש שמפתחותיו אינם רגישים לאותיות גדולות/קטנות - `$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 להאש המשמשת כאחסון האמיתי; ההוּוים ממירים את המפתח לאותיות קטנות לפני שהם נוגעים בו. שימו לב שהאיטרציה מחזירה את המפתחות *המאוחסנים* (באותיות קטנות), וזה בדיוק מה שהאש שאינו רגיש לאותיות גדולות/קטנות צריך לעשות. ## חוזה המתודות `TIEHASH classname, LIST` : הבנאי. מחזיר הפניה blessed - בדרך כלל אך לא בהכרח הפניה להאש - שהופכת לעצם הקשור. `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`; כדי להתאים להאש רגיל, החזירו את מה ש־`FETCH` היה מחזיר עבור אותו מפתח לפני הסרתו. `CLEAR this` : מופעל כאשר ההאש כולו מרוקן, בדרך כלל על ידי השמת הרשימה הריקה (`%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` : נקרא כאשר ההאש מוערך בהקשר סקלרי או בוליאני (`scalar %h`, `if (%h)`, ומאז 5.28 גם `keys %h` בהקשר בוליאני). החזירו ערך שהוא אמת כאשר ההאש אינו ריק ושקר כאשר הוא ריק. `DESTROY this` ו־`UNTIE this` : הוּוי ניקוי אופציונליים, זהים בתפקידם למקרה הסקלרי. `UNTIE` מכוסה תחת מלכודת ה־untie להלן. ## פרוטוקול האיטרציה זהו החלק של ממשק ההאש שאין לו מקבילה בממשק הסקלרי, והחלק שהכי הרבה פעמים משתבש. כאשר איטרציה של [`keys`](../../p5/core/perlfunc/keys.md), [`values`](../../p5/core/perlfunc/values.md), או [`each`](../../p5/core/perlfunc/each.md) מתחילה, זמן הריצה קורא ל־`FIRSTKEY` כדי לקבל את המפתח הראשון, ולאחר מכן ל־`NEXTKEY` שוב ושוב, מעביר בכל פעם את המפתח שהוחזר קודם, עד שמתודה מחזירה את הרשימה הריקה או `undef`. שניהם נקראים תמיד בהקשר סקלרי וצריכים להחזיר מפתח בלבד; זמן הריצה קורא ל־`FETCH` בעצמו כדי לקבל כל ערך. שני כללים שומרים על נכונות האיטרציה: - **`FIRSTKEY` חייב לאפס כל איטרטור פנימי.** כאשר האחסון המגבה הוא האש אמיתי, העריכו תחילה את `keys %$self` בהקשר ריק או סקלרי - זה מאפס את סמן ה־`each` של Perl לכל האש - ולאחר מכן קראו ל־`each`. ה־`my $reset = keys %$self` החד־פעמי בדוגמה עושה בדיוק זאת. דלגו עליו ו־`keys %h` חדש עלול להמשיך מהמקום שבו האיטרציה האחרונה נעצרה. - **אותתו על הסוף באמצעות הרשימה הריקה.** כאשר האחסון המגבה אינו האש אמיתי ואין לו `each` משלו, החזירו את הרשימה הריקה (או `undef`) ברגע שמסרתם את המפתח האחרון. ## מדוע כדאי להגדיר את `SCALAR` ללא מתודת `SCALAR`, זמן הריצה מנחש את ערך האמת של ההאש בהקשר בוליאני, והניחוש עלול להיות שגוי - בפרט, הוא עשוי לדווח על האש כלא ריק מיד לאחר שרוקנתם אותו באמצעות `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` (אם מוגדר). - פרוסת האש `@h{qw(a b)}` קוראת ל־`FETCH` פעם אחת לכל מפתח; אין הוו לפרוסה. ## מחלקה מינימלית בת־קיימא האש קשור לקריאה/כתיבה זקוק לכל הפחות ל־`TIEHASH`, `FETCH`, ו־`STORE`. אם הקוראים ירצו אי פעם לבצע עליו איטרציה, הוסיפו `FIRSTKEY` ו־`NEXTKEY` - בלעדיהם, `keys` ו־`each` רואים האש ריק. הוסיפו `EXISTS` ו־`DELETE` אם הקוראים משתמשים בפונקציות מובנות אלה; בלעדיהם, `exists`/`delete` מתים בנקודת השימוש. `SCALAR` ו־`CLEAR` משלימים את הנכונות עבור בדיקות בוליאניות ורִיקון בכמות. ## הדרך הקלה: לרשת מ־`Tie::StdHash` `Tie::StdHash` (המסופק בתוך `Tie::Hash`) ממש את התפריט כולו מעל הפניה blessed להאש. ירשו ממנו ודרסו רק את ההוּוים שצריכים להתנהג אחרת: ```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) - הפונקציה המובנית ותפריט מתודות ההאש המלא - [`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` - [סקלרים קשורים](scalars.md) - הממשק הפשוט יותר שזה נבנה עליו - `Tie::Hash` - מודול מחלקת הבסיס; `Tie::StdHash` היא הגרסה הקונקרטית