sub#
הצהרה או הגדרה של תת־שגרה.
sub היא מילת המפתח המציגה תת־שגרה. עם NAME ו־BLOCK היא מגדירה תת־שגרה בעלת שם בחבילה הנוכחית. ללא BLOCK היא הצהרה־מקדימה. ללא NAME היא ביטוי sub אנונימי שמוערך להפניית קוד - sub { ... } היא הצורה היחידה של sub שהיא בפועל ביטוי; הצורות בעלות־השם הן הצהרות ואינן מחזירות דבר שימושי.
תקציר#
sub NAME BLOCK # named definition
sub NAME (PROTO) BLOCK # with prototype
sub NAME : ATTRS BLOCK # with attributes
sub NAME (PROTO) : ATTRS BLOCK # prototype + attributes
sub NAME; # forward declaration
sub NAME (PROTO); # forward with prototype
my $ref = sub BLOCK; # anonymous, returns code ref
my $ref = sub (PROTO) : ATTRS BLOCK; # anonymous with proto + attrs
use feature 'signatures';
sub NAME ($x, $y = 0, @rest) BLOCK # named with signature
my $ref = sub ($x, $y) BLOCK; # anonymous with signature
מה מוחזר#
הצורות בעלות־השם (sub NAME BLOCK, sub NAME (PROTO) BLOCK, וכו«) הן הצהרות. הן מתקינות את תת־השגרה אל טבלת הסמלים של החבילה הנוכחית בזמן הידור ואינן תורמות דבר לביטוי הסובב. כתיבת my $x = sub foo { 1 }; היא טעות נפוצה - אלו שתי הצהרות מודבקות יחד, ו־$x נשאר לא־מוגדר.
הצורה האנונימית sub BLOCK היא ביטוי. הוא מוערך - בנקודה שבה הביטוי מגיע בזמן ריצה, לא בזמן הידור - להפניית קוד הסוגרת על המשתנים הלקסיקליים בתחום. אותו ביטוי sub { ... } שמוערך פעמיים מפיק שתי הפניות קוד נבדלות שאינן חולקות דבר:
my @refs = map { sub { $_ } } 1..3; # three independent closures
הצהרות מקדימות (sub NAME; ללא בלוק) אינן עושות דבר בזמן ריצה ואינן מחזירות דבר. תכליתן היא להודיע לפרסר על השם כך שקריאות מאוחרות יותר יוכלו להיפרסר ללא סוגריים.
מצב גלובלי שהוא נוגע בו#
החבילה הנוכחית (הנקבעת על־ידי
package) קובעת את השם המוסמך במלואו של תת־שגרה בעלת שם.sub foo { }בתוךpackage Acme;מתקין אתAcme::foo, לא אתmain::foo.@_בתוך הגוף מחזיק את רשימת הארגומנטים (alias לסקלרים של הקורא, פרט למקרה שחתימה בתוקף - ראו חתימות להלן). השמה ל־@_כשלם שוברת את ה־aliasing עבור שאר הקריאה.איברי
$_[N]הם aliases לסקלרים של הקורא. שינוי$_[0]משנה את משתנה הקורא; העברת ליטרל ושינוי$_[0]לאחר מכן היא שגיאה קטלנית.wantarrayבתוך הגוף משקף את ההקשר שבו תת־השגרה נקראה.
הגדרה בעלת שם#
sub greet {
my ($name) = @_;
return "Hello, $name";
}
print greet("world"), "\n"; # Hello, world
הגוף מהודר בזמן הידור. השם נראה מנקודה זו בקובץ ואילך; הפניות מקדימות בתוך אותה חבילה עובדות משום ש־Perl דוחה קריאות בסגנון מתודה ו־bareword.
הגדרה־מחדש של תת־שגרה בעלת שם בזמן ריצה (eval "sub foo { ... }" או sub foo { } שני באותה חבילה) מחליפה את ההגדרה הקודמת ופולטת אזהרת Subroutine foo redefined תחת use warnings. ניתן לדכא ב־no warnings 'redefine' לתחום ההגדרה־מחדש.
sub אנונימי וסגירות#
sub make_counter {
my $n = 0;
return sub { ++$n };
}
my $c = make_counter();
print $c->(), $c->(), $c->(), "\n"; # 123
ה־sub הפנימי לוכד את $n מהתחום המקיף שלו. כל קריאה ל־make_counter יוצרת $n טרי וסגירה טריה עליו.
my @doublers = map { my $k = $_; sub { $k * 2 } } 1..3;
print $doublers[2]->(), "\n"; # 6
שימו לב ל־my $k = $_ הביניים - סגירות לוכדות משתנים, לא ערכים, ו־$_ משותף בין איטרציות map. ללא ההעתקה, כל סגירה הייתה רואה את הערך האחרון של $_.
חתימות#
עם use feature 'signatures' (מופעל כברירת מחדל תחת use v5.36 ואילך), רשימת הפרמטרים מופיעה בין השם לבלוק, וארגומנטים נכרכים אוטומטית למשתנים לקסיקליים:
use feature 'signatures';
sub add ($x, $y) { $x + $y }
sub greet ($name, $greeting = "Hello") {
return "$greeting, $name";
}
sub log_all ($level, @msgs) {
print "[$level] $_\n" for @msgs;
}
צורות חתימה:
$x- פרמטר מיקומי נדרש.$x = EXPR- מיקומי אופציונלי עם ברירת מחדל;EXPRמוערך בכל קריאה כשהארגומנט חסר.$x = undef- אופציונלי, ברירת מחדל היאundef(שימושי לתיעוד שמשבצת היא ניתנת ל־null ולא מושמטת).@rest/%rest- slurpy, צורך את כל הארגומנטים הנותרים.$/@/%- מציין־מקום ללא שם, טוען מספר־ארגומנטים ללא כריכת משתנה.
קריאה עם מספר־ארגומנטים שגוי מקרקרת: Too many arguments for subroutine או Too few arguments for subroutine.
תחת חתימה, @_ עדיין קיים אך גישה אליו היא אזהרה תחת use warnings 'experimental::args_array_with_signatures' ב־Perl ישנים יותר ולא מומלצת ב־5.42. יש להשתמש במשתני החתימה במקום.
פרוטוטיפים#
sub mypush (\@@) {
my $aref = shift;
push @$aref, @_;
}
my @a = (1, 2);
mypush @a, 3, 4; # @a is now (1, 2, 3, 4)
פרוטוטיפים הם רמז לפרסר בזמן הידור, לא בדיקת טיפוס. הם משנים כיצד אתרי קריאה מפורסרים: \@ בפרוטוטיפ לעיל כופה שהארגומנט הראשון יהיה מערך ומעביר הפניה אליו. ראו prototype כדי לבחון את הפרוטוטיפ של תת־שגרה.
פרוטוטיפים אינם עושים דבר כאשר תת־השגרה נקראת דרך &name(...) או דרך הפניית קוד. אם רוצים חתימה, יש להשתמש ב־use feature 'signatures'; פרוטוטיפים וחתימות יכולים להתקיים יחד עם המאפיין :prototype(...):
use feature 'signatures';
sub each_pair :prototype(\@) ($aref) { ... }
מאפיינים#
מאפיינים מופיעים אחרי : ומשנים כיצד תת־השגרה מהודרת או נרשמת:
sub critical :lvalue { $state } # usable on the left of =
sub noop :method { } # marked as a method (for some tools)
מאפייני ליבה נפוצים: lvalue, method, prototype(...), const. מודולים כגון Attribute::Handlers מאפשרים לחבילה להגדיר משלה. מאפיינים לא־ידועים הם שגיאת זמן הידור.
הצהרה מקדימה#
sub later; # announce the name
plan later(3); # now parses without parens
sub later { ... } # defined later in the file
הצהרה מקדימה שימושית רק כדי לומר לפרסר ש־later היא תת־שגרה כך ש־later ARG יתפרסר כקריאה ולא כמבנה עצם־עקיף או ביטוי פסיק. היא אינה נדרשת אם קוראים עם סוגריים.
דוגמאות#
תת־שגרה בעלת שם, פירוק ארגומנטים מפורש:
sub area {
my ($w, $h) = @_;
return $w * $h;
}
print area(3, 4), "\n"; # 12
sub אנונימי המועבר לפונקציה מסדר גבוה:
my @lengths = map { sub { length shift } }->(@_),
("alpha", "beta", "gamma"); # not quite - see below
שימושי יותר: העברת sub ישירות:
use List::Util qw(first);
my $first_even = first { $_ % 2 == 0 } 1, 3, 4, 7; # 4
החזרה מובלעת - הערך של הביטוי האחרון מוחזר:
sub double { $_[0] * 2 } # no return needed
print double(21), "\n"; # 42
החזרה רגישה להקשר:
sub names {
my @n = qw(alice bob carol);
return wantarray ? @n : scalar @n;
}
my @all = names(); # ("alice","bob","carol")
my $n = names(); # 3
שינוי ארגומנטי הקורא דרך aliasing של @_:
sub upcase_in {
for (@_) { $_ = uc }
}
my $s = "hello";
upcase_in($s);
print $s, "\n"; # HELLO
רקורסיה עם __SUB__ - הפניה לתת־השגרה הנוכחית ללא לתת לה שם:
use feature 'current_sub';
my $fact = sub {
my $n = shift;
$n < 2 ? 1 : $n * __SUB__->($n - 1);
};
print $fact->(5), "\n"; # 120
מקרי קצה#
הגדרת
subבעלת שם היא הצהרה, לא ביטוי. היא אינה תורמת דבר לביטוי המקיף שלה.my $x = sub foo {};מתפרסר כשתי הצהרות;$xנגמרundef.הצורות
sub NAME BLOCKהן זמן הידור. גוף הבלוק מפורסר ומהודר כאשר הקובץ המקיף או ה־evalמהודרים. תופעות לוואי בתוך הבלוק רצות רק כאשר תת־השגרה נקראת, לא כאשר היא מוגדרת. בניגוד לכך,sub BLOCK(אנונימי) מוערך בזמן ריצה בכל פעם שמגיעים לביטוי, ומפיק סגירה חדשה בכל פעם.תת־שגרות מקוננות בעלות שם אינן סוגרות על שום דבר שימושי.
subהמוגדר בתוךsubאחר עדיין מותקן בחבילה בזמן הידור ואינו לוכד לקסיקליים מהקריאה המקיפה. כל קריאה לתת־השגרה החיצונית רואה את אותה תת־שגרה פנימית, עטופה סביב הלקסיקליים של הקריאה הראשונה. יש להשתמש ב־sub אנונימי לסגירות.returnמסיים הוא אופציונלי אך מפורש הוא ברור יותר. ללאreturn, הערך של הביטוי האחרון מוחזר. אם ההצהרה האחרונה היא לולאה או בלוק, ערך ההחזרה אינו מוגדר - אין להסתמך עליו.השמה כוללת ל־
@_שוברת aliasing.@_ = @_או@_ = (1, 2)מחליפים את המערך ומאוחר יותר$_[0] = Xלא מגיע יותר אל הקורא.העברת ליטרל ואז שינוי
$_[0]היא קטלנית.upcase_in("x")מת עםModification of a read-only value attemptedמשום ש־$_[0]הוא alias לליטרל.הגדרה־מחדש של sub פולטת
Subroutine X redefinedתחתuse warnings. עטיפת הגדרה־מחדש דורשתno warnings 'redefine'לתחום:no warnings 'redefine'; *Foo::bar = sub { ... };
subבתוך בלוקBEGINמוגדר בזמן הידור של היחידה המקיפה, כמו כל הצהרתsub; עטיפת ה־BEGINאינה משנה את התזמון של ההצהרה עצמה.פח של פרוטוטיפ אחרי רווח.
sub foo ($$)עםuse feature 'signatures'מתפרסר כחתימה, לא כפרוטוטיפ. כדי לצרף פרוטוטיפ תחת חתימות, יש להשתמש ב־sub foo :prototype($$) ($x, $y) { ... }.
הבדלים מהמעלה־הזרם#
תאימות מלאה עם Perl 5.42 מהמעלה־הזרם.
ראו גם#
return- חזרה מפורשת מתת־שגרה; בלעדיו ערך הביטוי האחרון מוחזרwantarray- בחינת הקשר הקריאה (רשימה / סקלר / void) מתוך הגוףcaller- מידע על מי קרא לתת־שגרה זו ומהיכןprototype- קריאה חזרה של הפרוטוטיפ של sub בעל שם או אנונימי__SUB__- הפניה לתת־השגרה הנוכחית ללא לתת לה שם; הכלי לרקורסיה אנונימיתmy- הדרך הרגילה לפרק את@_ללקסיקליים בעלי שם כשלא משתמשים בחתימותmethod- הצהרת מתודה בתחביר מחלקה; השקול שלsubלמתודות תחתuse feature 'class'