זרימת בקרה · מחלקות ותכנות מונחה־עצמים

method#

הצהרה על מתודת מופע בעלת שם בתוך בלוק class.

method מגדיר תת־שגרה שמצפה להיות מופעלת על עצם של המחלקה העוטפת. הוא מתנהג כמו sub, עם שתי הבטחות נוספות ש־sub אינו מעניק: ה־$self הלקסיקלי קשור ל־invocant באופן אוטומטי, וחתימות תמיד מופעלות - כותבים פרמטרים כאילו use feature 'signatures' היה בתוקף, ו־$self אינו מופיע בחתימה הזו.

method תקף רק בתוך הצהרת class. מחוץ לבלוק class זוהי שגיאת זמן־הידור.

הערה

תכונה ניסיונית מילות המפתח class, method ו־field הן חלק מתכונת ה־class הניסיונית (הוצגה ב־Perl 5.38). הפעלתה עם use feature 'class'; מנפיקה אזהרה בקטגוריה experimental::class. התחביר והסמנטיקה עדיין עשויים להשתנות בין מהדורות של Perl.

תקציר#

method NAME BLOCK
method NAME SIGNATURE BLOCK
method NAME : ATTRS BLOCK
method SIGNATURE BLOCK       # anonymous
method BLOCK                 # anonymous

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

method בצורתו בעלת השם הוא הצהרה, לא ביטוי - הוא מתקין את המתודה בטבלת המתודות של המחלקה העוטפת ומוערך לכלום שימושי במיקום ההוראה. הצורה האנונימית מחזירה הפניית קוד שזוכרת את הקשר המחלקה וניתן לקרוא לה מאוחר יותר עם invocant של עצם.

לגוף של method קוראים עם העצם כ־invocant. ערך ההחזרה של המתודה הוא מה שהבלוק מחזיר, על־פי אותם כללי הקשר כמו קריאה לתת־שגרה רגילה.

מה ש־method נותן ש־sub אינו נותן#

ארבעה דברים שונים מכתיבת sub בתוך בלוק class:

  • $self מוצהר מראש. $self לקסיקלי נוצר בתחום המתודה ומאותחל ל־invocant. אין - ואין צורך - לבצע shift עליו מ־@_.

  • חתימות תמיד מופעלות. אפשר לכתוב method greet($name) { ... } ללא use feature 'signatures'. ה־invocant $self נצרך לפני שהחתימה נקשרת, ולכן הוא לעולם אינו מופיע ברשימת הפרמטרים.

  • שדות בתחום. משתני field שהוצהרו במחלקה העוטפת נראים בשמותיהם הלקסיקליים בתוך גוף המתודה. sub פשוט בתוך בלוק class אינו רואה שדות.

  • הוא רשום כמתודה. טבלת המתודות של המחלקה רושמת את השם, וזה מה שמנגנון פתרון המתודות מחפש עבור dispatch של $obj->name(...). sub פשוט בתוך בלוק המחלקה הוא עוזר, לא מתודה.

במילים אחרות: sub בתוך בלוק class הוא תת־שגרת חבילה רגילה שבמקרה חיה במרחב השמות של אותה חבילה. אין לו $self, אין נראות שדות, והוא אינו חלק מממשק המתודות של המחלקה - יש לקרוא לו דרך ClassName::helper(...) אם מוכרחים, לא דרך חץ.

דוגמאות#

מחלקה מינימלית עם מתודה ושדה:

use v5.38;
use feature 'class';
no warnings 'experimental::class';

class Greeter {
    field $greeting = "Hello";

    method greet($name) {
        return "$greeting, $name";
    }
}

my $g = Greeter->new;
say $g->greet("world");           # Hello, world

ברירות מחדל של חתימה עובדות בדיוק כפי שהן עובדות עבור sub:

class Greeter {
    field $greeting = "Hello";

    method greet($name = "someone") {
        return "$greeting, $name";
    }
}

say Greeter->new->greet;          # Hello, someone

מתודה ללא פרמטרים עדיין משתמשת בצורת החתימה - ה־() הריקים אינם נדרשים, אך מותרים והם הסגנון הנפוץ כאשר המתודה מקבלת ארגומנטים במקומות אחרים במחלקה:

class Counter {
    field $n = 0;

    method inc        { $n++ }
    method value ()   { return $n }
}

מתודה אנונימית - שימושית כמפעל או כ־callback שזקוק לגישה ל־$self ולשדות:

class AnonMethodFactory {
    method make_printer {
        return method { say "called on $self" };
    }
}

מתודה לקסיקלית (פרטית) המוצהרת עם my method. יש להפעיל אותה דרך אופרטור ->&, אשר עוקף את חיפוש המתודה וקורא ללקסיקלי ישירות כאילו הייתה מתודה:

class LexicalMethod {
    my method _check ($x, $y) {
        return $x > 0 && $y > 0;
    }

    method process ($x, $y) {
        return unless $self->&_check($x, $y);
        # ...
    }
}

sub רגיל בתוך מחלקה, בניגוד ל־method - ה־sub הוא עוזר, ה־method הוא הממשק הציבורי:

class Temperature {
    field $celsius;

    sub _c_to_f ($c) { $c * 9 / 5 + 32 }   # helper, no $self, no fields

    method fahrenheit {
        return _c_to_f($celsius);
    }
}

מקרי קצה#

  • מחוץ לבלוק class זוהי שגיאת זמן־הידור. method foo { ... } ברמת העל, או בתוך package שאינו class, אינו מתפענח. יש להשתמש שם ב־sub.

  • $self הוא קריאה־בלבד במובן שלא ניתן להצהיר על לקסיקלי אחר באותו שם בראש המתודה - הוא כבר בתחום. השמה ל־$self (לדוגמה $self = ...) מותרת אך נדרשת לעיתים נדירות ואינה משנה את ה־invocant של הקורא.

  • @_ אינו רשימת הארגומנטים שאתם מצפים לה. תחת החתימות ש־method מפעיל, @_ בתוך הגוף ריק לאחר שהחתימה נקשרת, בדיוק כמו בכל תת־שגרה שמשתמשת בחתימה. יש לקרוא פרמטרים מהחתימה, לא מ־@_.

  • סדר פתרון המתודות נקבע על־ידי המחלקה העוטפת. method עצמו אינו לוקח אפשרות MRO; ירושה ו־dispatch עוקבים אחר מה שהצהרת class הגדירה דרך :isa ומאפיינים קשורים.

  • method אינו משתתף ב־prototypes. מתודות מופעלות דרך dispatch, לא דרך קריאות ישירות לטבלת הסמלים, ולכן prototypes (המאפיין :prototype(...) על sub) חסר השפעה כאן. יש להשתמש בחתימה כדי להגביל את צורת הקריאה.

  • מאפיינים. הצורה method NAME : ATTRS BLOCK מקבלת מאפיינים באותה דרך כמו sub NAME : ATTRS BLOCK. סט המאפיינים השימושיים על מתודות עדיין מתייצב עם תכונת ה־class; יש להתייעץ ב־upstream לפני הסתמכות על מותאמים אישית.

  • מלכודת מתודה־אנונימית בהחזרה־ממתודה. return method { ... } מחזיר הפניית קוד. method { ... } כביטוי האחרון של מתודה ללא return הוא עדיין הפניית קוד, אך קוראים לעיתים קרובות מבינים אותו בטעות כבלוק - יש להעדיף return מפורש לבהירות.

הבדלים מ־upstream#

תואם מלא ל־upstream Perl 5.42.

תכונת ה־class - ולכן method - מסומנת כניסיונית ב־upstream; pperl יורש סטטוס זה ואת קטגוריית האזהרה experimental::class.

ראו גם#

  • class - מצהיר על החבילה ש־method חי בתוכה; method מתפענח רק בתוך בלוק class

  • field - משתנים לכל־מופע שנראים בשם בתוך כל method של המחלקה העוטפת

  • sub - הצהרה על תת־שגרה רגילה; להשתמש בה עבור עוזרים בתוך מחלקה שאינם זקוקים ל־$self או לגישה לשדות

  • __CLASS__ - שם המחלקה הנוכחית, שימושי בתוך מתודות הזקוקות ל־dispatch בחזרה לקוד ברמת המחלקה

  • return - החזרה מפורשת מגוף מתודה; מומלץ כאשר הביטוי האחרון הוא בעצמו צורה אנונימית של method { ... }

  • my - הקדם my ל־method כדי להצהיר על מתודה לקסיקלית (פרטית) המופעלת דרך ->&