תיחום

local#

שומר את הערך הנוכחי של משתנה חבילה ומשחזר אותו ביציאה מהתחום הסובב.

local הוא אופרטור התחום הדינמי. הוא אינו מצהיר על משתנה חדש - הוא נשלח לתוך משתנה חבילה (גלובלי) קיים, גונז את הערך הנוכחי במחסנית שמירה מוסתרת, ודואג שהערך המקורי יוחזר כשהבקרה עוזבת את הבלוק הנוכחי, eval, או do FILE. תת־שגרות הנקראות רואות את הערך הזמני. עבור רוב הצרכים של ״אני רוצה משתנה מקומי לבלוק הזה״, הכלי הנכון הוא my; פנו ל־local ספציפית כשהמשתנה חייב להיות גלובלי לחבילה - משתני הפיסוק, מטפלי קובץ, או רשומות בטבלת הסמלים - ואתם רוצים שלאותו גלובלי יהיה ערך שונה במשך בלוק וכל תת־שגרה שהוא קורא לה.

תקציר#

local EXPR
local $var
local $var = EXPR
local (@list) = LIST
local $hash{key}
local $array[i]
local *GLOB

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

הערך של הביטוי שעבר localize (הערך החדש, לאחר כל השמה באותה הצהרה). ניהול מחסנית השמירה הוא תופעת לוואי; ערך ההחזרה חשוב רק כאשר local מופיע בתוך ביטוי גדול יותר:

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

תחום דינמי, לא תחום לקסיקלי#

local ו־my הם זנים שונים של תיחום:

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

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

זו הסיבה ש־local הוא הכלי הנכון עבור משתני פיסוק כמו $/, $\, $,, $_, ו־$@: אלה גלובלים של חבילה ש־runtime של Perl (וכל דבר שנקרא מהקוד שלכם) קורא בשמות ידועים. הצללה של my לא הייתה משפיעה עליהם.

sub slurp {
    my ($path) = @_;
    open my $fh, "<", $path or die "open $path: $!";
    local $/;                     # undef $/ for this sub only
    return <$fh>;                 # read to EOF in one go
}

שורת local $/ למעלה היא הניב הנפוץ ביותר של local בקוד אמיתי: ביטול הגדרת מפריד רשומת הקלט באופן זמני כך ש־readline (<$fh>) יחזיר את הקובץ כולו. כאשר slurp חוזרת, $/ משוחזר לכל מה שהיה לפני - גם אם הקורא שינה אותו גם.

מה ניתן ומה לא ניתן ל־localize#

ניתן לעשות localize ל־:

  • סקלרים, מערכים, והאשים של חבילה - local $Pkg::var, local @Pkg::arr, local %Pkg::hash. local $var כ־bareword מכוון אל המשתנה בחבילה הנוכחית.

  • משתני our שכבר הוצהרו - our יוצר כינוי לקסיקלי למשתנה חבילה, אז local עליו עושה localize לגלובלי הבסיסי.

  • אלמנטים בודדים ופלחים של מערכים/האשים של חבילה - local $hash{key}, local $array[3], local @hash{qw(a b)}, local @array[0..2].

  • Globs - local *name יוצר רשומת טבלת־סמלים חדשה כך ש־$name, @name, %name, &name, ומטפל הקובץ name כולם מאופסים דינמית יחד.

  • lvalues מותנים - local ($cond ? $v1 : $v2) כאשר הענף הנבחר עצמו ניתן ל־localize.

אינכם יכולים לעשות localize ל־:

  • משתנה my. משתני my הם לקסיקליים החיים ב־pad, לא בטבלת הסמלים; אין להם שם חבילה ש־local יוכל לשמור תחתיו. ניסיון לעשות זאת הוא שגיאת זמן־הידור: Can't localize lexical variable $x.

  • משתנה state. אותה סיבה.

  • גלובלים קסומים לקריאה־בלבד. local $1 = 2 נכשל עם Modification of a read-only value attempted - משתני הלכידה אינם ניתנים להשמה. (היוצא־דופן הוא $_: local $_, מאז 5.14, מסיר במפורש קסם כך שניתן להשתמש בו מחדש בבטחה בתת־שגרה.)

Localize של אלמנטים מטיפוס מורכב#

local $hash{key} ו־local $array[i] שומרים את החריץ הנקוב, לא את הערך שבמקרה נמצא שם. כאשר התחום מסתיים, הערך המקורי משוחזר לאותו חריץ - גם אם האלמנט נמחק או שהמערך התקצר בינתיים. מפתח האש שנמחק קופץ חזרה; אלמנט מערך שעבר pop חוזר להופיע, מרפד את המערך ב־undef במידת הצורך.

our %hash = (a => "is");
{
    local $hash{a} = "drill";
    delete $hash{a};              # gone for now...
}
print $hash{a}, "\n";             # ...but restored to "is"

דוגמאות#

בסיסי: לתת לגלובלי ערך זמני לבלוק אחד. תת־שגרות הנקראות מתוך הבלוק רואות את הערך החדש.

our $verbose = 0;
sub log_msg { print "[v=$verbose] $_[0]\n" }

{
    local $verbose = 1;
    log_msg("inside");            # prints "[v=1] inside"
}
log_msg("outside");               # prints "[v=0] outside"

הניב slurp-a-file עם $/:

my $content = do {
    open my $fh, "<", $path or die "open $path: $!";
    local $/;                     # list context for <> now reads all
    <$fh>;
};

לכוד באופן זמני את $@ כך ש־eval פנימי לא ידרוס את השגיאה הממתינה של הקורא:

sub try_cleanup {
    local $@;                     # caller's $@ preserved
    eval { risky_cleanup() };
    # even if eval failed, caller's $@ is untouched
}

ברירות מחדל ל־print בסגנון Python, מתוחמות לבלוק אחד:

{
    local $, = " ";
    local $\ = "\n";
    print 1, 2, 3;                # "1 2 3\n"
}
print 1, 2, 3;                    # "123" - defaults restored

צורת רשימה דורשת סוגריים. הסוגריים גם נותנים לאגף הימני הקשר רשימה - בדיוק כמו my:

our (@wid, %get);
local (@wid, %get) = (@defaults, %overrides);

Localize של אלמנט האש בודד - שימושי להשחלת דריסות דרך קריאה מבלי לגעת במפתחות לא־קשורים:

our %config = (timeout => 30, retries => 3);
{
    local $config{timeout} = 5;
    do_probe();                   # sees timeout => 5
}
# %config back to (timeout => 30, retries => 3)

Localize של glob - רשומת טבלת־סמלים שלמה עבור LOG מוחלפת:

{
    local *LOG;
    open LOG, ">", "/tmp/trace.$$" or die $!;
    run_traced();                 # sees our private LOG filehandle
}
# original LOG (if any) is back

מקרי קצה#

  • אופרטור של זמן ריצה, לא הצהרה. local מבוצע כל פעם שהבקרה מגיעה אליו. בתוך לולאה הוא שומר ומשחזר בכל איטרציה - תקורה מדידה. הוציאו אותו מהלולאה כאשר הכוונה היא ״עבור הלולאה כולה״:

    { local $/ = "\n\n";            # once, not per iteration
        while (<$fh>) { ... }
    }
    
  • ההשמה מוערכת לפני השמירה. האגף הימני רץ בתחום הדינמי הסובב, אז local $x = $x + 1 קורא את ה־$x הישן, ואז שומר, ואז משייך את הערך החדש.

  • גבול התחום הוא דינמי, לא לקסיקלי. השמירה מבוטלת כאשר הבלוק הנוכחי יוצא בזמן ריצה, לא כאשר בלוק המקור מסתיים טקסטואלית. יציאה דרך return, die, last, next, או goto לא־מקומי עדיין מפעילה את השחזור.

  • local על my הוא שגיאת זמן־הידור. המפענח דוחה את my $x; local $x; עם Can't localize lexical variable $x. השתמשו ב־our (או שם מלא) אם אתם זקוקים באמת לתיחום דינמי על אותו שם.

  • מערכים והאשים שעברו tie אינם מתנהגים כעת באופן שה־POD מתאר - localize של האגרגט כולו מלא־באגים במקור. localize של אלמנטים בודדים של אגרגט שעבר tie הוא בטוח. הסתייגות זו עוברת בירושה מ־Perl המקורי.

  • גלובלים קסומים לקריאה־בלבד אינם ניתנים להשמה. local $1 = "x" מת בזמן ריצה. אתם יכולים local $_ (קסם מוסר מאז 5.14) אבל לא local $1, local $&, וכו׳.

  • אינדקסים שליליים של מערך ב־local $array[-1] מתועדים כ״במיוחד מפתיעים״ במקור; התייחסו להתנהגות כבלתי־יציבה והימנעו.

  • delete local מרחיב את local להסרת אלמנט: delete local $hash{key} מוחק את הרשומה עבור הבלוק הנוכחי ומשחזר אותה ביציאה. הוא מחזיר את הערך שהיה שם לפני ה־localization.

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

תאימות מלאה עם Perl 5.42 המקורי.

ראו גם#

  • my - הצהרה לקסיקלית (זמן־הידור, בתחום בלוק); הכלי הנכון כשרוצים משתנה פרטי באמת

  • our - כינוי לקסיקלי למשתנה חבילה; שותף נפוץ ל־local כאשר הגלובלי בחבילה אחרת

  • state - לקסיקלי קבוע; אינו ניתן ל־localize

  • delete - בשילוב עם local (delete local $h{k}) לתחימת מחיקת אלמנט לבלוק הנוכחי

  • eval - יעד local נפוץ: local $@ סביב eval פנימי מונע ממנו לדלוף שגיאות לקורא

  • $/ - מפריד רשומת קלט; יעד local קנוני לקריאות קובץ במצב slurp

  • $_ - סקלר ברירת מחדל; local $_ מסיר קסם (מאז 5.14) כך שתת־שגרה יכולה להשתמש בו מחדש בבטחה

  • $@ - שגיאת ה־eval האחרונה; local $@ מגן על הקורא מפני שגיאת eval פנימי