זרימת בקרה

next#

התחלה מיידית של האיטרציה הבאה של הלולאה העוטפת.

next הוא המקבילה של Perl להוראת continue של C: הוא נוטש את שאר גוף האיטרציה הנוכחית וקופץ לשלב האיטרציה של הלולאה. אם ללולאה יש בלוק continue, בלוק זה רץ תחילה, אז הביטוי הבוקר נבדק מחדש (או האלמנט הבא נלקח עבור foreach), והביצוע מתחדש בראש הגוף. עם תווית, next LABEL מכוון ללולאה עוטפת ספציפית במקום לפנימית ביותר.

תקציר#

next
next LABEL
next EXPR

מה מקבלים בחזרה#

שום דבר. next הוא אופרטור בקרת־זרימה, לא ביטוי - הוא משחרר אל מחוץ לאיטרציה הנוכחית ולכן לעולם לא מניב ערך לקוראו. ניסיון להשתמש בו במיקום מייצר־ערך (למשל כצד ימין של הצבה בתוך eval {}, sub {}, או do {}) הוא שימוש שגוי: המבנה הסובב לעולם אינו מסתיים באופן רגיל, ולכן אין ערך החזרה לצפות בו.

כיוון ללולאה#

ללא תווית, next מתייחס ללולאה העוטפת הפנימית ביותר (while, until, for, foreach, או בלוק חשוף, שנספר כלולאה חד־פעמית). עם תווית הוא מתייחס ללולאה הנקובה בשם, לא משנה כמה עמוק ה־next יושב בתוך לולאות אחרות:

OUTER: for my $row (@grid) {
    for my $cell (@$row) {
        next OUTER if $cell eq 'skip-row';
        process($cell);
    }
}

next EXPR, זמין מאז Perl 5.18, מעריך את EXPR בזמן ריצה ומשתמש בערכו המחרוזתי כשם התווית. אחרת הוא מתנהג בדיוק כמו next LABEL:

my $target = pick_label();
next $target;                   # same as: next FOO if $target eq "FOO"

השתמשו בצורת זמן הריצה במשורה - next LABEL סטטי קל יותר לקריאה ואימות חזותי.

אינטראקציה עם בלוקי continue#

בלוק continue של לולאה רץ בסוף כל איטרציה, בין אם איטרציה זו הסתיימה כרגיל ובין אם דרך next. זוהי כל מטרת הבלוק continue: הוא מקבץ את הרישומים שחייבים לקרות בכל מעבר.

my $i = 0;
LINE: while (my $line = <$fh>) {
    next LINE if $line =~ /^\s*#/;  # skip comments
    process($line);
}
continue {
    $i++;                            # runs even for skipped lines
}

last מדלג על בלוק ה־continue; next לא. זוהי התכונה הפשוטה ביותר המבדילה בין השניים, והסיבה ש־continue קיים כמבנה משלו במקום להיות מוטמע בגוף הלולאה.

דוגמאות#

לולאת while בסיסית - השלכת שורות הערה, עיבוד השאר:

while (my $line = <$fh>) {
    next if $line =~ /^\s*#/;
    next if $line =~ /^\s*$/;       # blank
    handle($line);
}

foreach עם מצבר - דילוג על רשומות שנכשלות בפרדיקט:

my $total = 0;
for my $n (@values) {
    next unless defined $n;
    next if $n < 0;
    $total += $n;
}

לולאות מקוננות עם תווית - מעבר לשורה החיצונית הבאה ברגע שמזהים זקיף בסריקה הפנימית:

ROW: for my $row (@grid) {
    for my $cell (@$row) {
        next ROW if $cell eq 'END';
        count($cell);
    }
}

בלוק continue שתמיד רץ, גם ב־next:

my @kept;
ITEM: for my $x (@input) {
    next ITEM if $x->{hidden};
    push @kept, $x;
}
continue {
    log_seen($_);                    # every $x is logged, kept or not
}

יציאה מבלוק חשוף - { ... } עצמאי הוא לולאה חד־פעמית, כך ש־next קופץ מעבר להוראות הנותרות ויוצא ממנו:

{
    last_chance() or next;           # bare block: next == fall out
    commit();
}

מקרי קצה#

  • אסור בתוך grep / map / בלוק־ערך do { }. מבנים אלה אינם לולאות - הבלוק שלהם מוערך עבור ערכו, ולא מבוצעות עליו איטרציות במובן בקרת־לולאה. שימוש ב־next ליציאה מהם הוא שימוש שגוי ומצוין במפורש ב־perlfunc של upstream. השתמשו בביטוי תנאי במקום זאת:

    my @kept = grep { wanted($_) } @xs;           # not: grep { next unless ... }
    my @mapped = map { transform($_) // () } @ys; # empty list == skip
    
  • לא return. next אינו יכול להעביר ערך מחוץ לבלוק מחזיר־ערך כמו eval { }, sub { }, או do { }. אם מוצאים את עצמכם פונים אל next ליציאה מבלוק כזה, רצוי return, או תנאי שמייצר את הערך הדרוש.

  • בלוק חשוף הוא לולאה חד־פעמית. { ... } ללא קידומת while / for הוא סמנטית לולאה שרצה בדיוק פעם אחת, כך ש־next יוצא ממנה. זה שימושי לעתים בתבניות יציאה־מוקדמת, אך last הוא הבחירה השכיחה יותר משום שהוא מבהיר את הכוונה.

  • תווית לא־מוכרת היא שגיאה קטלנית. next NOSUCH מת בזמן ריצה עם Can't "next" outside a loop block כאשר אף לולאה עוטפת אינה נושאת תווית זו.

  • continue רץ ב־next, לא ב־last. זו הסיבה השכיחה להפתעות בעת ריפקטור: העברת רישומים מגוף הלולאה לתוך continue משנה התנהגות רק עבור last, לא עבור next.

  • מוזרויות קדימות ופירוס. בניגוד לרוב האופרטורים הנקובים בשם, ל־next יש קדימות זהה להצבה, והוא פטור מכלל ה־״נראה־כמו־פונקציה״. משמע ש־next ("foo") . "bar" מעביר "foobar" ל־next, ולא רק "foo". השתמשו בסוגריים באופן מגונן כאשר שם התווית מגיע מביטוי:

    next(($cond ? "A" : "B"));
    
  • Thread־ים, אותות, הורסים. next משחרר את התחום הלקסיקלי של האיטרציה הנוכחית: משתני my יוצאים מהתחום, ערכי local משוחזרים, ו־DESTROY יורה על עצמים שיוצאים מהתחום, בדיוק כאילו האיטרציה הסתיימה כרגיל. מטפלי $SIG{...} ממתינים אינם מושפעים.

הבדלים מ־upstream#

תואם מלא ל־upstream Perl 5.42.

ראו גם#

  • last - יציאה מהלולאה העוטפת לחלוטין, תוך דילוג על כל בלוק continue

  • redo - אתחול מחדש של האיטרציה הנוכחית מבלי לבדוק שוב את התנאי ומבלי להריץ את continue

  • return - הכלי הנכון ליציאה מ־sub { }, eval { }, או do { } עם ערך; next אינו יכול לעשות זאת

  • grep - סינון רשימה; השתמשו בביטוי תנאי, לא ב־next, להשלכת אלמנטים

  • map - שינוי צורה של רשימה; החזירו את הרשימה הריקה () מהבלוק כדי להשליך אלמנט