זרימת בקרה

return#

עוזב את התת־שגרה הנוכחית, eval, do FILE, בלוק sort, או בלוק eval של regex, ומניב ערך לקורא.

return היא היציאה המפורשת מתת־שגרה בעלת שם או אנונימית. היא עוצרת את הערכת גוף התת־שגרה בנקודת הקריאה ומסירה את EXPR בחזרה למי שהפעיל את התת־שגרה. הערך ש־EXPR מייצרת תלוי בהקשר של הקורא - רשימה, סקלר, או void - אותו הגוף יכול לבדוק עם wantarray לפני שמחליטים מה להחזיר.

תקציר#

return EXPR
return

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

ל־return עצמה אין ערך החזרה - היא אינה ממשיכה במסגרת הנוכחית. היא מסיימת את המסגרת והקורא מקבל את EXPR, מוערך בהקשר של הקורא:

  • הקשר רשימה - EXPR מוערך בהקשר רשימה; ערך הרשימה שלו הוא מה שהקורא רואה.

  • הקשר סקלר - EXPR מוערך בהקשר סקלר; ערך הסקלר שלו הוא מה שהקורא רואה.

  • הקשר void - EXPR עדיין מוערך (לתופעות לוואי), אך הערך מושלך.

ללא EXPR הקורא מקבל:

  • הקשר רשימה - הרשימה הריקה ()

  • הקשר סקלר - undef

  • הקשר void - כלום

חוסר הסימטריה הזה חשוב: return; (חשוף) אינה אותו דבר כמו return undef;. return חשוף בהקשר רשימה מניב (), שהוא שקר ובעל אפס אברים; return undef; בהקשר רשימה מניב רשימה בת איבר אחד המכילה undef, שהיא אמת (כי לרשימה איבר אחד). תת־שגרות המאותתות שגיאה צריכות כמעט תמיד להשתמש ב־return חשוף.

sub find_it {
    my ($key) = @_;
    return unless exists $cache{$key};  # bare: () in list, undef in scalar
    return $cache{$key};
}

if (my @hits = find_it($k)) { ... }     # () is false; undef-in-list is true

התפשטות הקשר עם wantarray#

הקשר הקורא מגיע לנקרא דרך wantarray:

תת־שגרה הרוצה להחזיר ערכים המתאימים לצורה בודקת אותו:

sub stats {
    my @xs = @_;
    return unless @xs;                     # bare: () / undef as above
    my $sum = 0; $sum += $_ for @xs;
    my $avg = $sum / @xs;
    return wantarray ? ($sum, $avg) : $avg;
}

my ($s, $a) = stats(@data);                # list context  → two values
my $a       = stats(@data);                # scalar context → average only
stats(@data);                              # void context  → computed, discarded

אותו אתר קריאה יכול להיות מוערך בהקשרים שונים בהפעלות שונות; return פותר מחדש את EXPR בכל פעם.

החזרה מובלעת: הביטוי האחרון מנצח#

אם הבקרה מגיעה לסוף של תת־שגרה (או eval, או do FILE) מבלי לפגוש return, ערך הביטוי המוערך האחרון מוחזר, בהקשר של הקורא. זהו הסגנון הניבי של ”ביטוי נגרר“:

sub square { my ($x) = @_; $x * $x }      # implicit return of $x * $x

sub classify {
    my ($n) = @_;
    $n < 0   ? "negative"
  : $n == 0  ? "zero"
  : "positive"                             # trailing ternary is the value
}

יש להשתמש ב־return מפורש כשיוצאים מוקדם, או כשסוף התת־שגרה הוא משפט (לדוגמה, לולאה, השמה) שערכו אינו מה שרוצים שהקורא יראה.

דוגמאות#

יציאה מוקדמת על שומר:

sub lookup {
    my ($id) = @_;
    return unless defined $id;
    return $table{$id};
}

חזרה מבלוק eval מבלי לשחרר את התת־שגרה העוטפת:

sub try_parse {
    my ($text) = @_;
    my $parsed = eval {
        return {} if $text eq "";          # leaves eval, not try_parse
        parse($text);
    };
    return $@ ? undef : $parsed;
}

החזרה רגישת־הקשר:

sub users {
    return wantarray ? @all_users : scalar @all_users;
}

my @u = users();                           # the users themselves
my $n = users();                           # how many there are

חריגת מנתח - return אינה אופרטור נראה־כפונקציה:

sub greet { return ("hello") . " world" } # returns "hello world"
                                          # the . " world" is part of EXPR
greet();                                  # "hello world"

לכן return (EXPR) אינה מבודדת את EXPR מאופרטור נגרר; כל מה שאחרי הסוגר הסוגר הוא עדיין ארגומנט ל־return. אותו כלל כמו print.

אסור: return בתוך grep / map:

my @odd = grep { return $_ % 2 } @n;      # wrong; leaves the sub
my @odd = grep { $_ % 2 } @n;             # right

בתוך grep / map הביטוי האחרון של הבלוק הוא כבר הערך; return שם יוצא מ־התת־שגרה העוטפת, וזה כמעט אף פעם לא מה שמתכוונים אליו.

מקרי קצה#

  • return חשוף מול return undef: כאמור לעיל, return חשוף מניב () בהקשר רשימה, מה שמאפשר ל־if (my @x = f()) לעבוד כבדיקת ”אין תוצאות“. return undef שם איבר אחד ברשימה והופך את הבדיקה הזו לאמת. עדיף return חשוף אלא אם רוצים במיוחד סקלר defined-undef.

  • return ממשווה sort: לגיטימי ונפוץ במשווים מורכבים:

    sort { return $a->[0] <=> $b->[0] || $a->[1] cmp $b->[1] } @rows;
    
  • return מ־do FILE: הופך לערך הקובץ, וזה מה ש־require ו־use בודקים כדי להחליט על הצלחת טעינת מודול. .pm המסתיים ב־1; הוא הניב הנפוץ; return 1; בקרבת ראש הקובץ שקול.

  • return מבלוק (?{ ... }) של regex: מסיים רק את בלוק הקוד, לא את התאמת ה־regex. לעיתים נדירות שימושי; זרימת בלוק רגילה כמעט תמיד ברורה יותר.

  • תופעות לוואי בהקשר void עדיין מתרחשות: return expensive(); בהקשר void עדיין קורא ל־expensive(). return אינה רמז אופטימיזציה.

  • לא פונקציה, לא נדרשים סוגריים: return הוא אופרטור, לא פונקציה. return(1, 2, 3) ו־return 1, 2, 3 הם אותו דבר. חריגת המנתח לעיל פירושה שסוגריים סביב EXPR אינם מתחמים אותו מיתר המשפט - הסוגריים הם אך ורק לקיבוץ בתוך EXPR.

  • Return בצורת בלוק של eval: eval { return $x } עוזב את ה־eval עם $x; $@ מנוקה (אין חריגה). כדי להחזיר מהתת־שגרה העוטפת דרך חריגה, יש להשתמש ב־die במקום זאת.

הבדלים מהמקור#

תואם במלואו ל־Perl 5.42 במקור.

ראו גם#

  • wantarray - בודק את הקשר הקורא כך ש־return יוכל להניב את הצורה הנכונה

  • caller - החצי השני של אינטרוספקציית הקורא; שימושי כשתת־שגרה מחליטה מה להחזיר על סמך מי קרא לה

  • eval - return בתוך בלוק eval עוזב את ה־eval, לא את התת־שגרה העוטפת

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

  • die - יציאה לא־מקומית; יש להשתמש כשרוצים לשחרר מעבר למסגרות ביניים במקום להחזיר דרך כל אחת מהן

  • last - יוצא מלולאה, לא מתת־שגרה; אסור לבלבל בין השניים