wantarray#
מדווח על הקשר הקריאה של התת־שגרה המתבצעת כעת.
wantarray מאפשר לתת־שגרה לשאול את זמן הריצה איך הקורא שלה כתב את הקריאה: האם התוצאה הושמה לרשימה, לסקלר, או הושלכה? התשובה היא אחד משלושה ערכים נבדלים, ותת־שגרה יכולה להשתמש בה כדי להחזיר צורות שונות של נתונים, או לדלג על עבודה יקרה לחלוטין כאשר הקורא לא ביקש דבר.
תקציר#
wantarray
אינו לוקח ארגומנטים ואין לו צורת סוגריים - זוהי מילת מפתח, לא קריאת פונקציה.
מה מקבלים בחזרה#
wantarray מחזיר אחד מבדיוק שלושה ערכים, התואמים לשלושת ההקשרים ש־Perl מבחין:
ערך החזרה | הקשר של הקורא | תחביר קורא טיפוסי |
|---|---|---|
אמת ( | רשימה |
|
שקר ( | סקלר |
|
void |
|
ההבחנה התלת־כיוונית היא הסיבה שהפונקציה ”הייתה צריכה להיקרא wantlist()“: ההחזרה הנראית בוליאנית היא למעשה תלת־מצבית, ו־defined wantarray הוא הבדיקה הנכונה ל“האם הקורא רצה משהו בכלל“.
הניב הקנוני#
הדפוס ש־wantarray קיים בעבורו הוא תת־שגרה המתאימה את צורת ההחזרה שלה לקורא:
sub records {
my @rows = heavy_query();
return wantarray ? @rows : "@rows";
}
my @r = records(); # gets the list
my $s = records(); # gets a space-joined string
records(); # still runs heavy_query - see below
יש לזווג זאת עם יציאה מוקדמת כשהקורא לא ביקש דבר:
sub records {
return unless defined wantarray; # caller wrote `records();`
my @rows = heavy_query(); # skipped in void context
return wantarray ? @rows : "@rows";
}
defined wantarray הוא השומר של הקשר void. wantarray לבדו אינו - הוא שקר גם בסקלר וגם ב־void, ו־return מוקדם על wantarray שקר ישבור כל קורא של הקשר סקלר.
ההקשר מופץ, לא מפורש מחדש#
wantarray מדווח על ההקשר שהקורא כפה על התת־שגרה, לא מה שהתת־שגרה עושה באופן פנימי:
sub ctx { wantarray ? "list" : defined wantarray ? "scalar" : "void" }
my @a = ctx(); # "list"
my $s = ctx(); # "scalar"
ctx(); # "void"
print ctx(), "\n"; # "list" - print's LIST is list context
scalar ctx(); # "scalar" - scalar() forces scalar context
יש לשים לב לשני האחרונים: print כופה הקשר רשימה על ארגומנטיו, ו־scalar כופה במפורש הקשר סקלר. אף אחד מהם אינו עוסק במה ש־ctx עושה עם התוצאה.
קריאות מהקשר void#
תת־שגרה הנקראת כמשפט חשוף רצה בהקשר void, ו־wantarray מחזיר undef בתוך אותה תת־שגרה. זה אינו מדורג: תת־שגרה הנקראת מתוך תת־שגרה בהקשר void רואה את ההקשר ש־הקורא של עצמה כפה.
sub inner { defined wantarray ? "wanted" : "void" }
sub outer { my $x = inner(); return $x }
outer(); # outer is void; inner is scalar → "wanted"
כל אתר קריאה קובע את ההקשר שלו עצמאית. wantarray תמיד מדווח על ההקשר של התת־שגרה העוטפת הקרובה ביותר, לא על זה של השרשרת הדינמית.
עובד גם בתוך eval#
wantarray מדווח גם על ההקשר של בלוק eval או eval EXPR, לא רק על תת־שגרות בעלות שם:
my @x = eval { wantarray ? (1, 2, 3) : "scalar" }; # (1,2,3)
my $x = eval { wantarray ? (1, 2, 3) : "scalar" }; # "scalar"
eval { defined wantarray ? 1 : 0 }; # void → 0
זה אותו מנגנון - eval הוא מסגרת קריאה באותו מובן שתת־שגרה היא.
היכן ל־wantarray אין תשובה שימושית#
תוצאת wantarray היא לא מוגדרת במקומות אלה, וקוד לא צריך להסתמך על ערך מסוים:
רמת העל של קובץ (מחוץ לכל תת־שגרה).
בתוך בלוק
BEGIN,UNITCHECK,CHECK,INIT, אוEND.בתוך מתודת
DESTROY.
יש להתייחס ל־wantarray כמשמעותי רק בתוך תת־שגרה רגילה או eval. בכל מקום אחר, יש לעצב את הקוד כך שהתשובה לא תהיה משנה.
דוגמאות#
Getter המחזיר את הרשימה המלאה לקוראי רשימה, את הספירה לקוראי סקלר, ולא עושה דבר בהקשר void:
sub warnings {
return unless defined wantarray;
my @w = collect_warnings();
return wantarray ? @w : scalar @w;
}
my @all = warnings(); # every warning
my $count = warnings(); # just the number
warnings(); # collect_warnings() is not called
תת־שגרה המסרבת להיקרא בהקשר void כי ערך ההחזרה הוא כל העניין:
sub must_use {
defined wantarray
or croak "must_use: return value must be used";
return compute();
}
תת־שגרה המנפיקה איבר אחד לקריאה בהקשר סקלר ואת כל האצווה בהקשר רשימה - צורה שכמה ממשקי API בסגנון איטרטור חושפים:
sub next_batch {
state @queue;
@queue = refill() unless @queue;
return wantarray ? splice(@queue) : shift @queue;
}
מקרי קצה#
אין סוגריים, אין ארגומנטים.
wantarray()מנותח אך הסוגריים הריקים הם רעש; מילת המפתח אינה לוקחת דבר.wantarray $xהיא שגיאת תחביר, לא קריאה עם ארגומנט.לא הקשר הקורא עבור אופרטורים.
wantarrayמדווח רק על הקשר מסגרת הקריאה. ביטוי כמו$sub->() + 1מציב את הקריאה בהקשר סקלר;wantarrayבתוך$subרואה סקלר, כצפוי. אין דרך לשאול ”האם נקראתי בתוך ביטוי אריתמטי“ - רק רשימה / סקלר / void.returnמכבד את אותו הקשר.return @listבהקשר סקלר מניב את האיבר האחרון, לא את הספירה - מכיוון ש־returnעצמו רואה את הקשר הקורא. יש להשתמש ב־return wantarray ? @list : scalar @listכשרוצים את הספירה עבור קוראי סקלר.הקשר בוליאני הוא הקשר סקלר.
if (f())קורא ל־fבהקשר סקלר;wantarrayמחזיר שקר שם, לאundef.השמת רשימה לרשימה ריקה היא עדיין הקשר רשימה.
() = f();הוא הקשר רשימה למרות שהתוצאה מושלכת.wantarrayמחזיר אמת. זה שימושי לכפיית הקשר רשימה על תת־שגרה שתופעות הלוואי שלה תלויות בו.wantarrayאינו זמין באותה דרך לקוראי XS. XSUB בודק הקשר דרךGIMME_V; תת־שגרת Perl הנקראת מתוך XSUB רואה את ההקשר שה־XSUB קבע לקריאה.Prototypes אינם משנים את
wantarray. prototype($)כופה את ההקשר של ארגומנט, לא את הקשר הקריאה של התת־שגרה עצמה.
הבדלים מהמקור#
תואם במלואו ל־Perl 5.42 במקור.
ראו גם#
return- מכבד את אותו הקשר רשימה/סקלר/void ש־wantarrayמדווח עליו; השניים מתוכננים לשימוש יחדcaller- בדיקת מחסנית הקריאה עצמה (חבילה, קובץ, שורה, ובצורת שלושת הארגומנטים שלו, פרטי הקשר נוספים כולל האםwantarrayיחזיר אמת שם)scalar- כופה הקשר סקלר על ביטוי, שזה מה שגורם ל־wantarrayלהחזיר שקר בנקראeval- קובע מסגרת קריאה ש־wantarrayמדווח גם על הקשרה