תיחום

my#

מצהיר על משתנה אחד או יותר בתיחום לקסיקלי.

my introduces new variables whose visibility is bounded by the enclosing block, file, or eval. The compiler records the declaration at compile time; the storage is allocated and (re)initialised each time control enters the scope. Unlike local, my does not temporarily replace a package variable

  • it creates a genuinely new variable that exists only while the scope is live and is invisible outside it, including to any subroutines the scope calls.

תקציר#

my EXPR
my TYPE EXPR
my EXPR : ATTRS
my TYPE EXPR : ATTRS

משתנה יחיד עשוי להיכתב ללא סוגריים; רשימה של שניים או יותר חייבת להיות בסוגריים:

my $x;
my ($a, $b, @rest);
my Foo $obj;
my $x : shared = 0;

מה מקבלים בחזרה#

my היא הצהרה, לא אופרטור מייצר־ערך במובן הרגיל. במיקום rvalue היא מניבה את המשתנה שלה (או את רשימת המשתנים) כ־lvalue שניתן להשים אליו. הניבים הנפוצים הם:

my $x = $expr;              # scalar context on RHS
my ($first, @rest) = @list; # list context on RHS; destructuring
my @copy = @src;            # list context; @copy gets the elements
my %h = @pairs;             # list context; pairs populate the hash

כשלא ניתן מאתחל, כל משתנה מוצהר מתחיל כ־undef (סקלר), רשימה ריקה (מערך), או האש ריק.

תיחום ותוחלת חיים#

  • תיחום בלוק. משתנה my נראה מהנקודה שמיד אחרי הצהרתו עד סוף הבלוק העוטף הפנימי ביותר, הקובץ, eval, do, require, או קובץ שעבר use.

  • תיחום ביטוי־בקרה. הביטוי השולט של if / unless / elsif / else, while / until, for / foreach הוא חלק מהתיחום של ההצהרה הכלולה בו. ב־while (my $line = <$fh>) { ... } המשתנה $line חי לאורך כל גוף הלולאה ובלוק ה־continue שלה, אך לא מעבר לכך.

  • אחסון רענן בכל כניסה. בכל פעם שהבקרה נכנסת מחדש לתיחום, המשתנה נוצר מחדש. זה ההבדל המרכזי מ־state, השומר על ערכו לאורך כניסות.

  • Closures לוכדים אחסון, לא ערכים. תת־שגרה אנונימית הנוצרת בתוך התיחום שומרת על אותו מופע מסוים של המשתנה בחיים כל עוד התת־שגרה ניתנת לגישה.

sub make_counter {
    my $n = 0;
    return sub { ++$n };    # closes over this $n
}
my $c = make_counter();
$c->(); $c->();             # 1, 2

צורת רשימה ופירוק#

עם סוגריים, my מספקת הקשר רשימה לצד ימין ומפרקת את התוצאה:

my ($sec, $min, $hour) = localtime;
my ($head, @tail)      = @list;       # @tail absorbs the rest
my ($x, $y)            = ($y, $x);    # swap via list assignment

יש להשתמש ב־undef כמציין מקום כדי לדלג על מיקום:

my (undef, $min, $hour) = localtime;  # discard seconds

ללא סוגריים, my $foo היא הצהרת משתנה יחיד ואופרטור הפסיק חל על מה שבא אחריו:

my $foo, $bar = 1;          # WRONG: declares $foo only;
                            # $bar is the package variable
my ($foo, $bar) = (0, 1);   # Right.

מלכודות הקשר#

my אינה משנה איך הצד הימני מוערך - היא רק משנה את המשתנה בשמאל. my $foo סקלרי כופה הקשר סקלר; my (...) בסוגריים כופה הקשר רשימה:

my  $line  = <$fh>;         # scalar context: one line
my ($line) = <$fh>;         # list context: first of a list
my  @lines = <$fh>;         # list context: all remaining lines

הטעות הקלאסית היא כתיבת my ($foo) = <$fh> כאשר רצו שורה יחידה - הסוגריים מפעילים הקשר רשימה ומטפל הקובץ מחזיר רשימה בת איבר אחד; הערך במקרה הוא השורה הראשונה, אך ההקשר הסובב שגוי עבור כל מה שיבוא אחריו.

my מול local מול our מול state#

ארבע הצהרות, ארבע משמעויות שונות:

  • my - מציג משתנה לקסיקלי חדש. אינו נראה לקוד הנקרא. אחסון רענן בכל כניסה.

  • local - אינה מצהירה על דבר. היא שומרת את הערך הנוכחי של משתנה חבילה קיים ומחזירה אותו כאשר התיחום העוטף יוצא. נראה לקוד הנקרא דרך תיחום דינמי. יש להשתמש בו עבור החופן של גלובלים קסומים ($_, $/, $\, $,, $|, %ENV, …) שלא ניתן להפוך ללקסיקליים.

  • our - מצהיר על כינוי לקסיקלי למשתנה חבילה (גלובלי). האחסון חי בטבלת הסמלים של החבילה; our רק מאפשרת להתייחס אליו ללא קידומת החבילה לשאר התיחום הלקסיקלי. מספק את use strict 'vars'.

  • state - כמו my בנראות, אך האחסון נשמר לאורך כניסות חוזרות לתיחום. אתחול רץ פעם אחת; כניסות עוקבות משאירות את הערך בשקט.

package Counter;
our   $total = 0;           # package global; $Counter::total
my    $cache;               # lexical; invisible outside this file
state $calls = 0;           # lexical; keeps its value across calls
sub tick {
    local $\ = "\n";        # temporarily override output separator
    ++$calls;
    print ++$total;
}

נקודה קריטית: my $var אינו מסווה משתנה חבילה בעל אותו שם. משתנה החבילה נשאר נגיש דרך הצורה המוסמכת במלואה שלו כל עוד הלקסיקלי בתיחום:

package main;
our $x = 10;
my  $x = 20;
print "$x and $::x\n";      # "20 and 10\n"

TYPE ותכונות#

שתי הצורות הן חלק מהשפה אך הסמנטיקה שלהן עדיין מתפתחת (ניסוח המקור).

  • TYPE - שם מחלקה כ־bareword, קבוע שהוצהר דרך use constant, או __PACKAGE__. היסטורית נכבל ל־pragma של fields; לשימוש רגיל הוא משמש כרמז ואינו אוכף טיפוס בזמן ריצה.

    my Foo $obj = Foo->new;
    
  • ATTRS - רשימת תכונות המוצגת בנקודתיים המטופלת על ידי ה־pragma של attributes (ו־Attribute::Handlers מאז 5.8.0).

    my $x : shared;
    my @buf : Locked;
    

ראו L<perlsub/“Private Variables via my()“> במקור לניסוח הסמכותי.

ההצהרה עדיין לא בתיחום ב־RHS של עצמה#

המשתנה החדש המוצהר אינו נראה עד לאחר סיום המשפט המצהיר. זה הופך את הניב הזה למוגדר היטב:

my $x = $x;                 # new $x initialised from the old $x

ותנאי זה תלוי ב־$x חיצוני קיים מראש:

my $x = 123 and $x == 123;  # false unless the old $x was 123

בתוך משפט יחיד, אזכורים נוספים של השם מתייחסים לכבילה שלפני ההצהרה (או מעלים שגיאת strict 'vars' אם אין כבילה כזו):

our $x = 2;
foo($x, my $x = $x + 1, $x); # foo() receives (2, 3, 2)

דוגמאות#

כניסה טיפוסית לתת־שגרה - מתן שמות לארגומנטים:

sub distance {
    my ($x1, $y1, $x2, $y2) = @_;
    return sqrt( ($x2-$x1)**2 + ($y2-$y1)**2 );
}

אינדקס מקומי ללולאה עם for my:

for my $i (1 .. 10) {
    # $i is fresh each iteration; invisible after the loop
}

מצב פרטי בתיחום קובץ - המשתנה קיים למשך חיי המפרש אך אינו נגיש מחוץ לקובץ הזה:

my $cache = {};
sub lookup { $cache->{ $_[0] } //= _compute($_[0]) }

תת־שגרה פרטית דרך coderef לקסיקלי:

my $helper = sub { ... };
$helper->($x);

אזהרת הסתרה - הצהרה מחדש באותו תיחום מנפיקה אזהרה בקטגוריית shadow תחת use warnings:

use warnings 'shadow';
my $x = 1;
my $x = 2;                  # warning: "my" variable $x masks ...

מקרי קצה#

  • רק מזהים אלפא־נומריים. מובנים קסומים כגון $/, $_, $\, %ENV, @ARGV לא ניתן להפוך ללקסיקליים. יש להשתמש ב־local כדי לתחם אותם דינמית.

  • אין הסמכת חבילה. my $Foo::bar היא שגיאת תחביר: משתני my אינם בבעלות חבילה ואינם יכולים לשאת מסמיך ::.

  • סוגריים חסרים סביב רשימה. my $a, $b מצהיר רק על $a; $b הוא משתנה החבילה. יש להקיף בסוגריים תמיד שני שמות או יותר.

  • הפתעת הקשר רשימה. my ($line) = <$fh> כופה הקשר רשימה על הקריאה; ה־RHS היא רשימה בת איבר אחד, לא סקלר. יש להשמיט את הסוגריים אם רוצים סמנטיקה סקלרית.

  • foreach ללא my. for $i (...) ממקמת את $i דינמית באופן local. עדיף for my $i (...) כדי לתחום את האינדקס לקסיקלית.

  • הסתרה בלולאות. my בתוך גוף לולאה מצהיר על משתנה רענן בכל איטרציה. אם זה לא רצוי (לדוגמה, מונה שצריך לשרוד איטרציות), יש להצהיר עליו מחוץ ללולאה או להשתמש ב־state.

  • לכידת closure. closure על משתנה my שומר על אותו מופע מסוים בחיים. קריאות שונות לתת־שגרה עוטפת מייצרות closures עצמאיים על משתנים עצמאיים.

  • אינטראקציה עם use strict 'vars'. my מספקת strict-vars בתוך התיחום שלה; משתנים ללא הצהרה חייבים להיות our, מוסמכים במלואם, או מוצהרים מראש עם use vars.

  • זמן הידור מול זמן ריצה. כבילת השם מתרחשת בזמן הידור; המאתחל רץ בזמן ריצה, ורץ מחדש בכל כניסה לתיחום. מאתחלים יקרים בתוך לולאות חמות משלמים את העלות הזו בכל איטרציה.

הבדלים מהמקור#

תואם במלואו ל־Perl 5.42 במקור.

ראו גם#

  • our - כינוי לקסיקלי למשתנה חבילה; מספק את strict 'vars' מבלי ליצור אחסון חדש

  • local - שמירה/שחזור בתיחום דינמי של משתנה חבילה קיים; הכלי לגלובלים קסומים

  • state - לקסיקלי כמו my, אך אחסון נשמר לאורך כניסות חוזרות לתיחום

  • undef - מציין מקום ברשימת my בסוגריים, והערך ההתחלתי של סקלר לא־מאותחל

  • use strict - הופך את my / our / שמות מוסמכים במלואם לחובה, תופס גלובלים בשוגג

  • attributes - pragma המפרש את החלק : ATTRS של הצהרת my