תיחום · מחלקות ותכנות מונחה־עצמים
field#
מצהיר על משתנה לכל־מופע בתוך בלוק class.
field מציג משתנה חדש שהאחסון שלו פרטי לכל עצם של המחלקה הסובבת. כל מתודה וכל בלוק ADJUST של אותה מחלקה רואים את השדה כאילו היה lexical בתחום באותה נקודה - אבל הערך שכל אחד רואה הוא הערך השייך למופע הנוכחי. שדות הם תחליף של תכונת ה־class לניהול חריצי האש בהפניה ש־blessed עליה.
התכונה עדיין מסומנת ניסיונית ב־Perl 5.42 (ראו הבדלים מהמקור); הפעילו אותה עם use feature 'class'; והשתיקו את קטגוריית האזהרה עם no warnings 'experimental::class'; אם אינכם רוצים את הרעש.
תקציר#
field $scalar;
field $scalar = EXPR;
field @array : ATTRIBUTES;
field %hash : ATTRIBUTES = EXPR;
מה מקבלים בחזרה#
field היא הצהרה, לא ביטוי. היא אינה מפיקה ערך ואינה יכולה להופיע באגף הימני של דבר. כל הצהרת field מקצה חריץ אחד לכל מופע בפריסת המחלקה; החריץ הוא משתנה השדה עצמו, קשור למיקום אחסון לכל־עצם בכניסה לכל מתודה או בלוק ADJUST.
סקלרים, מערכים, והאשים - כולם מותרים:
class Thing {
field $scalar = 42;
field @array = qw(this is just an array);
field %hash = (species => 'Martian', planet => 'Mars');
}
היכן הצהרות שדה חוקיות#
רק ישירות בתוך בלוק class. field אינו declarator לשימוש כללי - הוא אינו חוקי בתוך גוף method, בלוק ADJUST, sub מקונן, או קוד package רגיל. המהדר דוחה אותו בכל מקום אחר:
class C {
field $ok; # OK
method m {
field $nope; # compile error
}
}
יש להצהיר על שדה לפני שניתן להתייחס אליו מכל מתודה או מאתחל בגוף אותה מחלקה.
מאתחלי שדה#
אם קיים = EXPR, הביטוי רץ פעם אחת לכל קריאת בנאי, לאחר שכל השדות שהוצהרו קודם לכן בגוף המחלקה אותחלו. הדבר חשוב כאשר ברירת המחדל של שדה מאוחר תלויה בשדה קודם:
class WithACounter {
my $next_count = 1;
field $count = $next_count++;
}
בתוך מאתחל, $self אינו קיים - העצם עדיין בבנייה. השתמשו בטוקן __CLASS__ כאשר המאתחל זקוק לשם המחלקה (לדוגמה, כדי לקרוא למתודת מחלקה שתת־מחלקות יכולות לדרוס):
class WithCustomField {
use constant DEFAULT_X => 10;
field $x = __CLASS__->DEFAULT_X;
}
class DifferentCustomField :isa(WithCustomField) {
sub DEFAULT_X { rand > 0.5 ? 20 : 30 }
}
מופע של DifferentCustomField יראה את __CLASS__ נפתר לשמו שלו, כך שהמאתחל יקלוט את DEFAULT_X הדרוס.
אטריבוטים של שדה#
אטריבוטים לאחר נקודתיים שולטים על האופן שבו השדה משתתף בבנייה והאם נוצרות עבורו מתודות גישה.
:param#
לקחת את ערך השדה מארגומנט בעל שם של הבנאי:
field $x :param;
field $y :param(the_y_value);
By default the parameter name is the field’s name with the sigil stripped ($x → x). An explicit name in parentheses overrides that. Without a defaulting expression the parameter is required
omitting it from
->new(...)throws. With a defaulting expression the parameter is optional, and three default operators are available:=- ברירת המחדל חלה רק כאשר הקורא השמיט את הפרמטר.//=- ברירת המחדל חלה גם כאשר הקורא העבירundef.||=- ברירת המחדל חלה גם כאשר הקורא העביר ערך שקר.
class Point {
field $x :param = 0; # default if omitted
field $y :param //= 0; # default if omitted or undef
field $z :param ||= 0; # default if omitted, undef, or 0
}
:reader#
מייצר מתודת גישה ללא ארגומנטים המחזירה את השדה. ללא שם מפורש המתודה נקראת על שם השדה (ללא sigil):
field $s :reader;
# equivalent to:
field $s;
method s () { return $s }
שם מפורש מותר:
field $x :reader(get_x); # method get_x () { return $x }
ניתן להחיל readers גם על שדות מערך והאש; בהקשר רשימה המתודה מניבה את התוכן, ובהקשר סקלרי את מספר האלמנטים - התנהגות ההקשר הרגילה של המשתנה הבסיסי:
field @users :reader;
...
scalar $instance->users; # count of users
:writer#
מייצר מתודת setter בעלת ארגומנט אחד המשייכת את הארגומנט שלה לשדה ומחזירה את ה־invocant (כדי לתמוך בשרשור). שם המתודה ברירת המחדל הוא שם השדה (ללא sigil) עם תחילית set_:
field $s :writer;
# equivalent to:
field $s;
method set_s ($new) { $s = $new; return $self }
שם מפורש מותר:
field $x :writer(write_x); # method write_x ($new) { ... }
:writer כעת עובד רק על שדות סקלריים; החלתו על שדה מערך או האש היא שגיאה קטלנית בזמן ההידור. בנו writers למערך או להאש ידנית.
מצב גלובלי שהוא נוגע בו#
אין ישירות. אחסון השדה חי על המופע, וביטויי המאתחל רצים בתחום של הבנאי - הם יכולים לקרוא כל משתנה הנראה בנקודת ההצהרה, אבל field עצמו אינו נוגע בשום משתנה מיוחד מתועד.
דוגמאות#
מחלקה מינימלית עם שדה אחד, מאותחל ב־ADJUST:
use feature 'class';
no warnings 'experimental::class';
class Greeter {
field $greeting;
ADJUST {
$greeting = "Hello";
}
method say_to ($name) {
say "$greeting, $name";
}
}
Greeter->new->say_to("world"); # Hello, world
פרמטרי בנאי דרך :param, עם תערובת של שדות חובה ושדות עם ברירת מחדל:
class Point {
field $x :param; # required
field $y :param = 0; # optional, defaults to 0
method as_string { "($x, $y)" }
}
Point->new(x => 3)->as_string; # (3, 0)
Point->new(x => 3, y => 4)->as_string; # (3, 4)
מתודות גישה הנוצרות אוטומטית מכסות את ה־boilerplate הנפוץ:
class Person {
field $name :param :reader;
field $age :param :reader :writer;
}
my $p = Person->new(name => "Ada", age => 36);
$p->name; # "Ada"
$p->age; # 36
$p->set_age(37); # returns $p
שדות מערך והאש עם ברירות מחדל:
class Bag {
field @items = ();
field %counts;
method add ($item) {
push @items, $item;
$counts{$item}++;
return $self;
}
method unique { keys %counts }
}
מאתחל התלוי בשדה קודם:
class Rect {
field $w :param;
field $h :param;
field $area = $w * $h; # evaluated after $w, $h are set
}
מקרי קצה#
הנראות הלקסיקלית היא לפי תחום מתודה, לא לפי תחום קובץ. שדה נראה מכל בלוק
methodאוADJUSTשל אותה מחלקה, ללא תלות בסדר קובץ המקור. הוא אינו נראה מהגדרותsubרגילות בתוך בלוק המחלקה - רק מ־method.לכל־מופע, לא לכל־מחלקה. לשני מופעים של אותה מחלקה יש אחסון עצמאי לכל שדה. השמה במופע אחד אינה משפיעה על אחר. אם אתם רוצים מצב כלל־מחלקתי, השתמשו במשתנה
myבתחום קובץ מחוץ לרשימת השדות.ה־sigil קובע את הטיפוס.
field $xהוא חריץ סקלרי,field @aחריץ מערך,field %hחריץ האש. בניגוד לעצמים מבוססי האש, אין דרך לשנות את טיפוס השדה בזמן ריצה; טיפוס המכל של החריץ קבוע על־ידי ה־sigil בהצהרה.$selfאינו זמין במאתחלים. העצם עדיין לא בנוי כאשר המאתחל רץ. השתמשו ב־__CLASS__לשם המחלקה, ודחו כל דבר הדורש את העצם המלא ל־ADJUST.סדר המאתחלים הוא סדר ההצהרה. מאתחלים מאוחרים יכולים להתייחס לשדות קודמים; ההפך הוא הפניה למשתנה לא־מאותחל.
:writerעל שדות שאינם סקלריים הוא קטלני בזמן ההידור. האטריבוט מוגדר רק לסקלרים ב־5.42; החלתו על@arrאו%hמבטלת את הידור המחלקה.:paramללא ברירת מחדל הוא חובה.Class->new()כשהפרמטר חסר משליך. הוסיפו= EXPR,//= EXPR, או||= EXPRכדי לעשותו אופציונלי.אין גישה חיצונית ישירה. ללא
:reader/:writer(או מתודה שנכתבה ידנית) שדה אינו נגיש מחוץ למחלקה - זוהי הכמסה שתכונת ה־class מספקת.אזהרת ניסיוניות. פירוק הצהרת
fieldמפיק אזהרתexperimental::classאלא אם הקטגוריה הזו מודחקת; ראו הבדלים מהמקור.
הבדלים מהמקור#
תאימות מלאה עם Perl 5.42 המקורי. המקור מסמן את תכונת ה־class - ולכן את field - כניסיונית; pperl עוקב אחר אותו סטטוס ומפיק את אותה אזהרת experimental::class. הבאגים הידועים במקור המופיעים ב־perlclass (segfaults סביב ירושה תוך־קובץ, אינטראקציות refaliasing, והכמסה דולפת) חלים באותה מידה על pperl.
ראו גם#
class- מצהיר על המחלקה שגופה הוא המקום היחיד שבוfieldחוקיmethod- צורת תת־השגרה היחידה שרואה משתני שדה לפי שםmy- הצהרה לקסיקלית רגילה; השתמשו בה למצב כלל־מחלקתי שלא צריך להיות לכל־מופעour- הצהרה גלובלית־לחבילה; השתמשו בה למצב גלובלי אמיתי שמחלקה רוצה לחשוףbless- הדרך שלפני 5.38 לבנות עצמים;fieldמחליף את ניהול חריצי ההאש שמחלקות מבוססות־blessנזקקו לוref- בדיקת מחלקה של עצם בזמן ריצה; עדיין עובד על מופעים המופקים על־ידי בנאיclass