מערכים · האשים

each#

לעבור דרך האש או מערך רשומה אחת בכל פעם.

each מקדם איטרטור פר־מכולה ומחזיר את הרשומה הבאה. עבור האש רשומה זו היא זוג (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 } }) בונה מכולה חדשה בכל איטרציה, כך שהאיטרטור תמיד טרי - הלולאה לעולם לא מסתיימת.

  • הצורה החשופה של each משייכת ל־$_; אם מסתמכים על $_ במקום אחר בגוף הלולאה, יש לשמור אותו עם local.

כל כניסה ללולאת while (each ...) קולטת את עמדת האיטרטור שהמכולה נמצאת בה. אין דרך לבודד את האיטרטור של הלולאה מקוד אחר שנוגע באותה מכולה. אם גוף הלולאה קורא לפונקציה שעשויה לקרוא את אותו האש, התבנית הבטוחה היא לולאת 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 בהקשר void - keys %h; - כדי לאלץ איפוס לפני הלולאה החדשה.

  • keys/values מאפסים את האיטרטור: כל קריאה ל־keys או values על אותו האש - כולל scalar keys %h בתוך גוף הלולאה - מאפסת את הסמן.

  • התייחסות בהקשר רשימה מאפסת את האיטרטור של האש, לא של מערך: my @flat = %h מאפס את הסמן של %h; המקבילה my @copy = @a לא נוגעת באיטרטור של @a.

  • מחיקה־במהלך־איטרציה אינה מוגדרת למעט הרשומה שהוחזרה לאחרונה. מחיקת מפתח אחר עלולה לגרום לרשומות להיות מבוקרות פעמיים או מדולגות לחלוטין.

  • הוספה־במהלך־איטרציה אינה מוגדרת - הוספת מפתח חדש באמצע הלולאה עשויה או לא להיות מבוקרת, ועלולה להפריע לסדר רשומות שעדיין לא נראו.

  • מכולה אנונימית בתנאי: each %{ +{ a => 1 } } או each @{ [1,2,3] } בונה מכולה טרייה בכל פעם שהתנאי מוערך, כך שהאיטרטור תמיד חדש והלולאה לעולם לא מסתיימת.

  • האשים ומערכים קשורים (tied) מאצילים ל־FIRSTKEY/NEXTKEY (האשים) או FETCHSIZE/FETCH (מערכים), כך שסדר האיטרציה הוא מה שהמחלקה הקשורה בוחרת ואף אחת מהערבויות לעיל אינה בהכרח בתוקף.

  • מוגדרוּת מול אמת בתנאי הלולאה: while (each %h) ו־while (my $k = each %h) שניהם בודקים מוגדרוּת של הביטוי, כך שמפתח "0" או "" אינו מסיים את הלולאה. זהו מקרה מיוחד עבור each במפורש.

  • ביטויים סקלריים: each $href על סקלר שמחזיק הפניה היה תכונה ניסיונית ב־5.14 והוסר ב־5.24. יש לבצע dereference במפורש: 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 - הלולאה הבטוחה יותר כאשר הגוף עלול לגעת במכולה; יש לשלב עם keys כדי לתפוס תמונת מצב קודם

  • sort - לשייך עם keys כאשר נדרש סדר איטרציה מוגדר; each לעולם לא ממיין