משתני ברירת מחדל#
שני משתנים מחזיקים את האופרנדים המשתמעים של Perl. $_ הוא הסקלר ברירת המחדל שאינספור מובנים קוראים כשהם נקראים ללא ארגומנט. @_ הוא מערך הארגומנטים של כל תת־שגרה. יחד הם אחראים לרוב ההפתעות מסוג ”מאיפה הגיע הערך הזה?“ בקוד Perl.
$_ - הסקלר ברירת המחדל#
$_ הוא הנושא: הערך שמדברים עליו כרגע. נתח עצום מהמובנים של Perl מתייעצים בו כשהם נקראים ללא ארגומנט מפורש:
for my $line (<$fh>) {
chomp; # chomp $line - but $line was aliased to $_
print if /\bERROR\b/; # print $_ if $_ =~ /\bERROR\b/
}
הרשימה המלאה של המובנים שמשתמשים ב־$_ כברירת מחדל כוללת את chomp, chop, lc, lcfirst, length, pos, print, printf, quotemeta, say, split (תבנית ברירת מחדל), study, uc, ucfirst, unlink, את האופרטורים m// ו־s///, את האופרטור tr///, ואת אופרטורי בדיקת הקובץ <>/-X. עמודי הפירוט שלהם מציינים את $_ כברירת המחדל; עמוד זה הוא התיאור הקנוני.
כינוי בתוך for ו־while#
לולאת ה־for (וה־foreach) מכנה את $_ לכל אלמנט ברשימה, בתורו:
my @items = (1, 2, 3);
for (@items) {
$_ *= 2; # mutates @items in place
}
# @items is now (2, 4, 6)
שינוי $_ בתוך הלולאה משנה את אלמנט הרשימה עצמו. זוהי התנהגות זהה ל־map, grep, any, all - וכן first ו־reduce מ־List::Util.
while (<$fh>) אינו מכנה - הוא קורא כל שורה לתוך $_ כעותק רענן. לא ניתן לדחוף בחזרה לקובץ על ידי השמה ל־$_ בלולאת while (<$fh>).
לוקליזציה של $_#
תת־שגרה הרוצה $_ משלה בלי להפריע לזה של הקורא חייבת לבצע local עליו:
sub categorise {
local $_ = shift; # decouple from caller's $_
return 'small' if /^\d{1,3}$/;
return 'medium' if /^\d{4,6}$/;
return 'large';
}
my @sizes;
for ('5', '12345', '999999999') {
push @sizes, categorise($_); # caller's $_ stays the loop alias
}
ללא ה־local, קריאה ל־categorise() עם shift הייתה עובדת - אך כל =~, /.../, או chomp בתוכה היו קוראים או כותבים בשקט את כינוי הלולאה, ושוברים את האיטרציה של הקורא.
$_ כ־lvalue#
$_ הוא משתנה סקלר אמיתי; ניתן להשים לו, לקחת אליו הפניה, ולהעביר אותו כ־lvalue:
$_ = 'hello';
chomp; # nothing to chomp; $_ unchanged
s/l/L/g; # $_ is now 'heLLo'
my $ref = \$_; # \$_ is the alias's address
$$ref = 'goodbye'; # mutates whatever $_ is currently bound to
שימו לב ש־$$ref השני יכתוב לערך כלשהו ש־$_ הוא כרגע - שבתוך לולאת for הוא אלמנט הרשימה הנוכחי. הפניות אל $_ שנלקחות מחוץ ללולאה ומשמשות בתוכה לעיתים רחוקות עושות את מה שהכותב התכוון אליו.
$_ לקסיקלי#
our $_ ו־my $_ היו תכונות ניסיוניות שהוסרו. $_ הוא תמיד הגלובל של החבילה; השתמשו ב־local $_ לבידוד.
@_ - ארגומנטים של תת־שגרה#
בתוך תת־שגרה, @_ הוא מערך הארגומנטים שהועברו לקריאה ההיא. כל אלמנט מכונה לביטוי של הקורא - @_ אינו עותק:
sub double {
$_[0] *= 2; # mutates the caller's variable
}
my $x = 5;
double($x);
# $x is now 10
זו הסיבה שרוב תת־השגרות מתחילות ב־my (...) = @_; - הפריקה יוצרת עותקים, ולאחריה השגרה אינה יכולה לשנות בטעות את מצב הקורא:
sub greet {
my ($name, $greeting) = @_; # decoupled from caller
$greeting //= 'Hello';
return "$greeting, $name!";
}
הכינוי שימושי לעיתים - כך chomp(@lines) משנה כל אלמנט במערך של הקורא - אך בקוד יומיומי ניב העותק־הפרוק הוא הכלל.
wantarray והקשר הקריאה#
תת־שגרה הרוצה להתנהג באופן שונה בהתאם לכך אם נקראה בהקשר סקלר, רשימה, או void בודקת את wantarray:
sub items {
return wantarray ? (1, 2, 3) : 3;
}
my @list = items(); # (1, 2, 3)
my $cnt = items(); # 3
items(); # void - return value discarded
@_ ו־wantarray הם שני חלקי תמונת מוסכמת הקריאה. @_ אומר מה הועבר; wantarray אומר מה מצופה בחזרה.
@_ לאחר shift, pop, unshift, push#
שינוי @_ עצמו (לא האלמנטים שלו) אינו בעל אפקט כינוי על הקורא - זהו משתנה מערך מקומי רגיל. shift @_ מסיר את הארגומנט הראשון, ומשאיר את השאר:
sub method_call {
my $self = shift; # standard OO pattern
my %args = @_; # rest of args as a hash
...
}
shift ללא ארגומנטים בתוך תת־שגרה משתמש ב־@_ כברירת מחדל, ולכן רואים my $self = shift; בכל מקום.
$_ = shift - רגע, מה?#
ניב מטעה נפוץ:
sub trim {
$_ = shift; # - set caller's $_ - DO NOT DO THIS
s/^\s+//;
s/\s+$//;
return $_;
}
אותו $_ = shift כותב ל־$_ הגלובלי של החבילה, שהוא נושא הלולאה של הקורא אם הקורא נמצא בתוך for. התיקון הוא ביצוע local, כמתואר לעיל:
sub trim {
local $_ = shift;
s/^\s+//;
s/\s+$//;
return $_;
}