משתני ברירת מחדל#

שני משתנים מחזיקים את האופרנדים המשתמעים של 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 $_;
}

ראו גם#

  • map, grep - הצרכנים הנפוצים ביותר של כינוי $_.

  • shift, pop - משתמשים ב־@_ כברירת מחדל בתוך תת־שגרה.

  • wantarray - הליווי של @_ בתמונת מוסכמת הקריאה.

  • local - הדרך הבטוחה לקבוע $_ בתוך תת־שגרה שהקורא עשוי לבצע איתה איטרציה.

  • איגוד regex - =~ הוא מה שמשתמשים בו כשלא רוצים את יעד $_ המשתמע.