חתימות#

חתימה היא רשימת פרמטרים בסוגריים הבאה מיד לאחר שם תת־השגרה (ולאחר כל מאפיין), במקום - או בנוסף ל - פירוק ה־@_ הידני של הגוף. חתימות מציגות משתני פרמטרים לקסיקליים, מבצעות בדיקת מספר־ארגומנטים בזמן הקריאה, ותומכות בערכי ברירת מחדל ובפרמטרים מסוג slurpy.

חתימות התייצבו ב־Perl 5.36; ב־5.42 הן תכונת ייצור הזמינה עם אחד מאלה:

use feature 'signatures';        # explicit feature import
use v5.36;                       # implicit (signatures + other 5.36 features)

PetaPerl תומך בתחביר החתימות המלא של 5.42.

צורה בסיסית#

use feature 'signatures';

sub add ($x, $y) {               # two mandatory positional parameters
    return $x + $y;
}

add(2, 3);                       # 5
add(2);                          # error: Too few arguments
add(2, 3, 4);                    # error: Too many arguments

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

זהו השיפור הקונקרטי ביותר על פני הצורה הקלאסית:

# Classic - silently accepts wrong arity
sub add {
    my ($x, $y) = @_;
    return $x + $y;
}

add(2);                          # $y is undef; later arithmetic warns
add(2, 3, 4);                    # third arg silently ignored

ברירות מחדל#

sub greet ($name, $greeting = 'Hello') {
    return "$greeting, $name!";
}

greet('Alice');                  # "Hello, Alice!"
greet('Alice', 'Hi');            # "Hi, Alice!"

ברירת המחדל היא ביטוי שרירותי המוערך בכל פעם שהפרמטר מושמט (כך ש־state וחישוב לכל קריאה שניהם עובדים). הוא יכול להתייחס לפרמטרים קודמים:

sub log_event ($message, $level = 'INFO', $prefix = "[$level]") {
    print "$prefix $message\n";
}

log_event('starting');                      # [INFO] starting
log_event('failure', 'ERROR');              # [ERROR] failure
log_event('done', 'OK', '>>');              # >> done

ברירת מחדל = undef שקולה בדיוק ל“אין ברירת מחדל“ מבחינת מספר הארגומנטים (הפרמטר עדיין אופציונלי) אך מתעדת את הכוונה. השתמש בשומרים בסגנון //= בתוך הגוף עבור הסמנטיקה של ”undef משמעו השתמש בברירת המחדל שלי“.

אופציונלי לעומת חובה#

פרמטרים הם חובה כברירת מחדל. פרמטר הופך לאופציונלי על־ידי:

  • מתן ערך ברירת מחדל ($x = 42).

  • הצבתו לאחר פרמטר אופציונלי אחר (טרנזיטיבי).

  • היותו ממשיך אחריו @arr או %hash מסוג slurpy.

אינך יכול שיהיה פרמטר חובה לאחר אופציונלי (למעט באמצעות slurpy):

sub bad ($x = 1, $y) { ... }     # error: Mandatory parameter follows optional

פרמטרים מסוג slurpy#

הפרמטר האחרון עשוי להיות @list או %hash מסוג slurpy. הוא בולע את כל הארגומנטים הנותרים:

sub join_all ($sep, @parts) {
    return join $sep, @parts;
}

join_all(', ', 'a', 'b', 'c');   # "a, b, c"

sub configure ($name, %opts) {
    $opts{verbose} //= 0;
    ...
}

configure('demo', verbose => 1, port => 8080);

ה־hash מסוג slurpy גם נכשל אם לרשימה הנותרת אורך אי־זוגי:

configure('demo', 'verbose');    # error: Odd-sized list given

זוהי התבנית השימושית ביותר שחתימות פותחות: ממשק API של פרמטרים בעלי שם עם מיקומי אחד בתוספת בליעת %opts.

פרמטרים אנונימיים#

$ (או @, %) ללא שם הוא מציין־מקום מיקומי:

sub second ($, $x) { return $x }

second('ignored', 'kept');       # "kept"

זה שימושי במידה מתונה בעת התאמת callback לממשק המספק יותר ארגומנטים ממה שאכפת לך מהם.

שילוב ברירות מחדל ו־slurpy#

sub render ($template, $cache = 1, %opt) {
    ...
}

render('greeting.tt');                       # cache=1, %opt empty
render('greeting.tt', 0);                    # cache=0, %opt empty
render('greeting.tt', 1, locale => 'de');    # all three
render('greeting.tt', locale => 'de');       # ERROR: 'locale' becomes $cache
                                             # then 'de' is the lone slurp arg
                                             # (odd-length hash) - diagnose carefully

המקרה האחרון הוא המלכודת: פרמטר מיקומי אופציונלי שאחריו hash מסוג slurpy הוא דו־משמעי עם קריאות שיש בהן רק ארגומנטים בעלי שם. או שתסיר את המיקומי האופציונלי ותשים הכל ב־hash, או שתעביר תמיד את המיקומי האופציונלי במפורש.

מעבר מפירוק @_#

התרגום המכני:

# Before
sub make_user {
    my ($name, $email, %extra) = @_;
    ...
}

# After
use feature 'signatures';
sub make_user ($name, $email, %extra) {
    ...
}

אתה מקבל בדיקת מספר־ארגומנטים ולקסיקלים בעלי שם בחינם. הגוף נותר ללא שינוי.

המקומות שבהם אינך יכול לתרגם מכנית:

  • הגוף משתמש במספר הארגומנטים באופן דינמי (if (@_ >= 3)) - חתימות מקבעות את מספר הארגומנטים בזמן הניתוח, אז עבד מחדש לפרמטר אופציונלי עם ברירת מחדל.

  • הגוף משנה את $_[0] עבור אפקט ה־aliasing - שמור על הצורה הקלאסית, מכיוון שחתימות מציגות העתקים, ושוברות את ה־alias.

  • הגוף משתמש ב־goto &other ורוצה להעביר את ה־@_ המקורי - @_ עדיין מאוכלס תחת חתימות ב־5.42, אך זוהי התנהגות מוגדרת־מימוש ועשויה להשתנות. שמור על הצורה הקלאסית עבור העברת קריאות־זנב.

חתימות ו־prototypes אורתוגונליים#

חתימות ו־prototypes פותרים בעיות שונות:

מנגנון

משפיע על

מתי נבדק

שימושי עבור

חתימה

מבט הגוף

זמן ריצה

מספר ארגומנטים, פרמטרים בעלי שם

prototype

כיצד המנתח מנתח

זמן הידור

חיקויי DSL

לתת־שגרה יכולים להיות שניהם, כאשר ה־prototype נכתב כמאפיין:

use feature 'signatures';
sub mygrep :prototype(&@) ($code, @list) {
    grep { $code->($_) } @list;
}

mygrep { /foo/ } @items;         # prototype lets us drop `sub`
                                 # signature gives us $code and @list

ה־prototype מעצב את אתר הקריאה; החתימה מעצבת את הגוף. הם אינם משכפלים זה את זה.

הסיבה הגדולה ביותר לעבור#

תפיסת קריאות בעלות מספר־ארגומנטים שגוי ברגע שהן קורות - לא כמה שורות מאוחר יותר כשאתה סוף סוף מבצע $y + 1 ונתקל באזהרה על ערך undef. חתימות הופכות מחלקה של באגים עדינים להודעת שגיאה ברורה.

ראו גם#

  • ארגומנטים ו־@_ - המנגנון הקלאסי שחתימות מתקיימות לצידו.

  • Prototypes - מנגנון שונה, מבולבל לעתים קרובות עם חתימות.

  • sub - עמוד ה־perlfunc של מילת המפתח.

  • הצהרה - היכן חתימות יושבות בתחביר ההצהרה.

  • תיחום - פרמטרי חתימה הם לקסיקלים בסגנון my.