last#
יציאה מיידית מלולאה, תוך דילוג על שאר הגוף ועל בלוק ה־continue.
last הוא המקבילה של Perl ל־break של C. הוא מעביר את השליטה אל מחוץ ללולאה העוטפת אל ההוראה הבאה אחריה. ההוראות הנותרות באיטרציה הנוכחית אינן רצות, וגם לא בלוק ה־continue של הלולאה - זהו ההבדל המהותי מ־next. ללא ארגומנט הוא מכוון ל־while, until, for, foreach או בלוק ריק העוטפים הפנימיים ביותר; עם LABEL הוא מכוון ללולאה מתויגת מעבר לכך.
תקציר#
last
last LABEL
last EXPR # LABEL computed at runtime, since 5.18
מה מקבלים בחזרה#
כלום. last מבצע בקרת זרימה; הוא אינו מייצר ערך. לא ניתן להשתמש בו כדי להחזיר תוצאה מבלוק שבדרך־כלל מניב כזו, כמו eval { ... }, sub { ... } או do { ... }. בהקשרים אלה הקונסטרוקט אינו מייצר ערך, או שהתוכנית מתה עם Can't "last" outside a loop block - ראו מקרי קצה להלן.
כיוון ללולאה לפי תווית#
ללא תווית, last מתייחס ללולאה העוטפת הפנימית ביותר. זה בדרך־כלל מה שרוצים:
while (my $line = <$fh>) {
last if $line =~ /^__END__$/;
process($line);
}
עם תווית ניתן לפרוץ מלולאה חיצונית מתוך לולאה מקוננת. תוויות הן באותיות גדולות כמוסכמה:
OUTER: for my $row (@grid) {
for my $cell (@$row) {
last OUTER if $cell eq 'STOP';
}
}
# control resumes here
last EXPR (Perl 5.18+) מחשב את התווית בזמן ריצה. EXPR חייב להעריך למחרוזת שמציינת תווית עוטפת:
my $target = 'OUTER';
last $target;
אינטראקציה עם בלוקי continue#
בלוק ה־continue של לולאה רץ בדרך־כלל בסוף כל איטרציה, כולל האחרונה. last מדלג עליו - זהו ההבדל המגדיר מ־next:
my $i = 0;
while ($i < 10) {
last if $i == 3;
print "body $i\n";
} continue {
$i++; # runs after every iteration EXCEPT
# the one terminated by last
}
# prints body 0, body 1, body 2; then exits the loop.
# $i stays at 3 because continue did not fire the final time.
אם רוצים ש־continue ירוץ, יש להשתמש ב־next עם שומר במקום, או לקדם את המונה לפני ה־last.
התנהגות בלולאות מקוננות#
last עוזב רק לולאה אחת בכל פעם - הפנימית ביותר, אלא אם תויגה. בדוגמה זו ה־last הפנימי יוצא מה־for אבל ה־while ממשיך לרוץ:
while (1) {
for my $x (1 .. 5) {
last if $x == 3;
}
# control lands here every iteration of the while
last; # needed to exit the while as well
}
כדי לשחרר מספר רמות בבת־אחת, יש לתייג את הלולאה החיצונית ולכוון אליה:
SEARCH: for my $file (@files) {
open my $fh, '<', $file or next;
while (my $line = <$fh>) {
if ($line =~ /$pattern/) {
$found = $file;
last SEARCH; # exits both the while and the for
}
}
}
בלוקים ריקים נחשבים ללולאות#
בלוק { ... } ריק הוא, לצורכי בקרת זרימה, לולאה שמבוצעת בדיוק פעם אחת. last יכול לצאת מבלוק כזה מוקדם, וזו הדרך האידיומטית לכתוב ״לנסות סדרת בדיקות, לצאת בהתאמה הראשונה״:
{
last if $cached;
recompute();
store_in_cache();
}
# control continues here
זוהי הצורה היחידה של last שאינה כרוכה בקונסטרוקט מאיטר.
דוגמאות#
הפסקת קריאת קובץ בשורה ריקה - האידיום הקלאסי של סיומת־כותרת:
LINE: while (<$fh>) {
last LINE if /^$/;
push @header, $_;
}
מצא־ודווח על־פני מבנה דו־ממדי:
my $hit;
ROW: for my $r (0 .. $#grid) {
for my $c (0 .. $#{ $grid[$r] }) {
if ($grid[$r][$c] eq $needle) {
$hit = [$r, $c];
last ROW;
}
}
}
יציאה מוקדמת מבלוק ריק המשמש כרצף נסה־פעם־אחת:
my $result;
{
$result = $cache{$key}, last if exists $cache{$key};
$result = compute($key);
$cache{$key} = $result;
}
תווית מחושבת (Perl 5.18+). נדרשת לעיתים נדירות, אך שימושית כשלולאת היעד נבחרת דינמית:
my $level = $deep ? 'OUTER' : 'INNER';
OUTER: for (...) {
INNER: for (...) {
last $level if $done;
}
}
מקרי קצה#
אסור בתוך
grepו־map. שניהם מצפים שהבלוק שלהם יפיק ערך עבור כל איבר קלט;lastשולל זאת. המפענח מקבל את הקוד (הבלוק אינו לולאה לקסיקלית שהוא יכול לראות דרכה), אך הרצתו מתה עםCan't "last" outside a loop block. יש לסנן עם תנאי בתוך הבלוק במקום, או לעבור ללולאתforמפורשת.do { ... }אינו לולאה.lastבתוךdo { ... }אינו מסיים את ה־do; הוא משחרר עד הלולאה האמיתית העוטפת הקרובה ביותר. אם אין כזו, התוכנית מתה עםCan't "last" outside a loop block. ליציאה מוקדמת מ־doהמשמש כביטוי, ראו את העקיפות ב־perlsyn תחת ”Statement Modifiers“ - בדרך־כלל בלוק ריק עםlast, או לולאתforחד־פעמית.sub { ... }אינו לולאה.lastבתוך גוף תת־שגרה אינו חוזר מתת־השגרה; הוא משחרר מעבר לתת־השגרה אל הלולאה העוטפת ב־caller. יש להשתמש ב־returnכדי לעזוב תת־שגרה.lastבתוךevalאינו בורח מה־eval.eval { ... }כשלעצמו אינו לולאה, ולכןlastמסתכל החוצה מעבר ל־evalאחר הלולאה העוטפת הקרובה ביותר ומשחרר אליה. ה־evalנסגר כתוצר־לוואי של אותו שחרור, אך$@נשאר ריק - לא הועלתה חריגה. אם ל־evalאין לולאה עוטפת מעליו, התוכנית מתה עםCan't "last" outside a loop block. כדי לעזובevalבצורה רגילה, יש ליפול אל הסוף או להשתמש ב־die(נתפס על־ידי ה־evalעצמו) או ב־return(אם ה־evalבתוך תת־שגרה ורוצים לעזוב את תת־השגרה).קדימות. בניגוד לרוב האופרטורים בעלי השם, ל־
lastיש קדימות זהה לזו של השמה והוא פטור מכלל looks-like-a-function. לכןlast ("foo") . "bar"מעביר את"foo" . "bar"כתווית, לא רק"foo". יש להשתמש ברווח, או להשמיט את הסוגריים, כדי להימנע מהפתעות:last LABEL; last "LABEL";
תווית לא־ידועה.
last NOPEכאשר אין לולאה עוטפת המתויגתNOPEמתה עםLabel not found for "last NOPE". זוהי שגיאת זמן־ריצה, לא שגיאת זמן־הידור - התווית נפתרת מול מחסנית הקריאות הדינמית.צורת modifier של לולאה אין בלוק לצאת ממנו.
EXPR if CONDוצורות דומות של statement-modifier אינן לולאות;lastבתוך הביטוי משחרר מעברן.
הבדלים מ־upstream#
תואם מלא ל־upstream Perl 5.42.
ראו גם#
next- מדלג לאיטרציה הבאה, מריץ קודם את בלוק ה־continue; המקבילה ל־lastששומרת את הלולאה חיהredo- מפעיל מחדש את האיטרציה הנוכחית ללא בדיקת התנאי מחדש וללא הרצתcontinuereturn- עוזב תת־שגרה עם ערך; הכלי הנכון כשמושיטים יד ל־lastבתוךsub { ... }continue- בלוק ה־loop-trailer ש־lastמדלג עליו ו־nextמכבד; ראו את עמודו לאיור התלת־צדדי שלlast/next/redo