ארגומנטים ו־@_#
כשתת־שגרה נקראת בדרך הקלאסית (ללא חתימה), Perl משטחת את כל רשימת הארגומנטים למערך יחיד וחושפת אותו בתוך הגוף כ־@_. אברי המערך הזה אינם העתקים - הם aliases לביטויי הקורא. כלל יחיד זה הוא מקור רוב ההפתעות של מוסכמת הקריאה של Perl ורוב עוצמתה של מוסכמת הקריאה.
כלל ה־aliasing#
sub bump {
$_[0]++; # mutates the caller's variable
}
my $x = 10;
bump($x);
say $x; # 11
שינוי $_[0] כותב דרך ה־alias אל כל מה שהקורא העביר. זה מתוכנן - כך chomp(@lines) מצליח להסיר תווי שורה חדשה מכל אבר של @lines ולא מהעתק של @lines.
ה־aliasing משתרע גם על ליטרלים, עם השלכות צפויות:
bump(10); # error: Modification of a read-only
# value attempted
הליטרל 10 הוא קבוע. ה־alias מצביע אליו; ניסיון השינוי מת.
ניב הפירוק#
מכיוון שה־aliasing הוא לעתים רחוקות מה שהגוף רוצה, כמעט כל תת־שגרה בסגנון הקלאסי מתחילה באחת משתי התבניות האלה:
# Named arguments (most common)
sub greet {
my ($name, $greeting) = @_; # COPY into private lexicals
$greeting //= 'Hello';
return "$greeting, $name!";
}
# Method dispatch
sub method_call {
my $self = shift; # COPY first arg, leave rest in @_
my %args = @_; # remaining args as a hash
...
}
לאחר הפירוק, הגוף עובד עם העתקים פרטיים ואינו יכול לשנות בטעות את מצב הקורא. shift ללא ארגומנט בתוך תת־שגרה מקבל כברירת מחדל את @_, ולכן my $self = shift; נמצא בכל מקום ב־Perl מונחה־עצמים.
שימושים לגיטימיים ב־aliasing#
aliasing הוא הכלי הנכון כשאתה אכן רוצה לשנות את מצב הקורא:
# in-place trim
sub trim_inplace {
for (@_) {
s/^\s+//;
s/\s+$//;
}
}
my @data = (" hello ", " world\n");
trim_inplace(@data);
# @data is now ("hello", "world")
הלולאה for (@_) עושה alias ל־$_ לכל אבר של @_, שהוא בעצמו alias לכל אבר של @data. שינויי ה־s/// עוברים דרך שני קפיצות ה־alias אל המחרוזות המקוריות. ללא ה־aliasing, אותה צורת קוד הייתה דורשת כפליים עבודה.
אותו מנגנון מניע את chomp(@lines), chop(@buf), וכל פונקציית ”עבוד על רשימה ושנה במקום“ שאתה כותב בעצמך. הצהר על הכוונה בשם הפונקציה (_inplace, mutate_, וכדומה) כדי שהקוראים לא יופתעו.
ארגומנטים בעלי שם#
ל־Perl אין תחביר מובנה של פרמטרים בעלי שם בצורה הקלאסית, אך ה־=> (הפסיק השמן) בתוספת השמת hash נותן את אותה תוצאה:
sub configure {
my %opt = @_; # ('host' => 'localhost', 'port' => 8080)
$opt{host} //= 'localhost';
$opt{port} //= 80;
...
}
configure( host => 'example.com', port => 8080 );
הפסיק השמן זהה בסמנטיקה לפסיק רגיל אך מצטט את ה־bareword משמאלו, כך ש־host => ... הוא קיצור של 'host' => .... ראה , עבור האופרטור עצמו.
עבור ארגומנטים בעלי שם מסוג חובה־פלוס־אופציונלי, הצורה הסטנדרטית היא:
sub render {
my ($template, %opt) = @_; # one positional, rest as named
$opt{escape} //= 1;
...
}
render('greeting.tt', escape => 0, locale => 'de');
עבור ניב הפרמטרים בעלי השם המודרני הבנוי על חתימות, ראה חתימות.
shift, pop, unshift, push על @_#
@_ הוא מערך אמיתי. אתה יכול לבצע shift מהקדמה, pop מהאחור, לחתוך אותו, לשנות אותו. אף אחד מאלה אינו משנה את מצב הקורא - רק כתיבה דרך $_[N] משנה.
sub describe {
my $what = shift; # remove first arg from @_
my @rest = @_; # copy what's left
...
}
sub method {
my $self = shift;
my @args = @_;
$self->dispatch(@args);
}
השלכה נוחה: אם ברצונך לארוז מחדש את הארגומנטים הנותרים כדי להעבירם לתת־שגרה אחרת, פשוט כתוב @_ - זה בדיוק מה ש־goto &other עושה ללא ההעברה המפורשת. ראה רקורסיה עבור העברת קריאות־זנב.
wantarray והקשר הקריאה#
בתוך תת־שגרה, wantarray אומר לך את ההקשר שבו בוצעה הקריאה:
| הקשר | צורה נפוצה |
|---|---|---|
| רשימה | החזר רשימה |
| scalar | החזר סקלר יחיד |
| void | החזר מוקדם; התוצאה תיזרק |
sub items {
return unless defined wantarray; # void: nothing to compute
my @result = compute_items();
return wantarray ? @result : scalar @result;
}
@_ אומר מה נכנס; wantarray אומר מה מצופה לחזור. הם שני החצאים של תמונת מוסכמת הקריאה. ראה lvalue והקשר עבור הדיון המלא.
מלכודות נפוצות#
my ($x) = @_לעומתmy $x = @_. הראשון הוא הקשר רשימה:$xמקבל את הארגומנט הראשון. השני הוא הקשר סקלר:$xמקבל את מספר הארגומנטים. הסוגריים משמאל הם ההבדל; טעויות כאן נפוצות.sub one_arg { my ($x) = @_; # $x = first arg } sub count_args { my $n = @_; # $n = number of args }
שינוי
$_[N]”בטעות“. פונקציות כמוchomp,chop,tr///,s///פועלות על הארגומנט שלהן במקום.chomp($_[0])משנה את מחרוזת הקורא. אם זה לא מה שאתה רוצה, העתק תחילה.השטחת מערכים ו־hashes. מערכים ו־hashes המועברים כארגומנטים מאבדים את זהותם באתר הקריאה - כולם הופכים לאברים של ה־
@_השטוח היחיד. כדי להעביר מערך ללא השטחה, העבר הפניה:takes_array(\@arr); # one ref argument sub takes_array { my ($aref) = @_; push @$aref, 'extra'; }
@_לאחרgoto &sub. ה־@_הנוכחי מועבר אל היעד. כל מה שכבר ביצעת עליוshiftנעלם מנקודת המבט של היעד. זוהי תכונה, לא באג - ראה רקורסיה.
ראו גם#
@_- הערך של המשתנה ב־perlvar, עם כלל ה־aliasing והדיון בהקשר הלולאה.חתימות - החלופה המודרנית לטיפול בפרמטרים בעלי־שם־ומיקומיים.
ערכי החזרה - מה שהגוף שולח בחזרה.
אופרטור הפסיק -
=>לבניית ארגומנטים בעלי שם.