פרק 11: הפניה להפניההפרמטרים שלך, בבקשהשימוש נפוץ מאוד בהפניות הוא להעברת מידע בין פונקציות ושגרות. במישור התאורטי, מרבית התוכניות המעוצבות היטב ב Perl, יכללו פונקציות, המבצעות פעולות ספציפיות ומוגדרות היטב. נניח ויש לנו תת-תוכנית הקרויה summary$, אשר מקבלת שתי פרמטרים: תווית (סקלר), ורשימת שמות משפחה. הפונקציה שלנו תיצור סוג של תרשים מהשמות ברשימה, כאשר התווית תהיה הכותרת שלו. הבעיה כאן היא הצורך להעביר סקלר אחד ורשימה אחת לתת התוכנית. יתכן והאינסטינקט שלכם יהיה לבנות קריאה כזו: print &summary($label,@surnames); אולם זו תהיה טעות. מדוע? כיוון שתת התוכנית מקבלת כפרמטרים רשימה שטוחה (flat list) לתוך משתנה רשימה מובנה _@; והמשמעות של זה היא שהקריאה הזו תקבל את הערך של label$ ואחריו כל אחד מהפריטים ב surnames@ כרשימה אחת ארוכה. בעוד שתת התוכנית שלכם תרצה לקבל שני ערכים; האחד סקלר, והשני רשימה. במקום זאת אנו רוצים להעביר הפניה לרשימה; היות וההפניה היא סקלר, היא מועברת בקלות לתוך תת התוכנית, אשר יכולה לבצע בתוכה ביטול הפניה. נשמע מבלבל? בואו נראה את הקוד: print &summary($label,\@surnames); והנה תחילת תת התוכנית: sub summary { my ($label,$surnameRef)=@_; my @surnames=@{$surnameRef}; print "Title: $label\n"; print join (",",@surnames); etc... } נקודה חשובה נמצאת בשורה השניה בקטע האחרון; שני משתנים מקומיים מקבלים פרמטרים מתוך הרשימה המגיעה _@. הפרמטר השני הינו סקלר מכיוון שהוא מקבל הפניה, ולפיכך surnameRef$ הופך להפניה למערך המוצבע ע"י surnames\@ . על מנת להשתמש בו בהקשר רשימתי, אנו צריכים לבצע ביטול הפניה, מה שמבוצע, כאן, ע"י ביצוע ביטול הפניה למשתנה surnameRef$ והשמתו לתוך משתנה רשימתי רגיל surnames@. יכולנו לבטל הפניה גם תוך כדי עבודה בפונקצית ה ()join,, פעולה שהייתה אפקטיבית יותר אולם ברורה פחות לקריאה: print join (",",@{$surnameRef}); כאשר אתם מעבירים נתונים בין תתי תוכניות, ניתן לראות את ההפניות ככלי יעיל לאריזת מבנה נתונים מסובך כדי להעביר את כולו לתת התוכנית, שיכולה לפתוח אותו - לבטל את ההפניה - לתוך מבנה נתונים, יהיה זה רשימה או האש. זכרו, כמובן, שהפניה מצביעה למידע, כך שאם המידע המוצבע ישתנה , המידע שתקבלו כאשר תבצעו ביטול הפניה ישתנה גם הוא. הבא נמשיך עם הדוגמא שלנו. בואו נניח שאנו רוצים להעביר האש מסוים לתוך תת תוכנית, אשר תחזיר לנו האש שונה. %grades=("Tom Jones"=>92,"Briget Gidget"=>85); $label="Grade Summary"; print &summary($label,\%grades)->{"header"}; print "<TABLE>".&summary($label,\%grades)->{"body"}."</TABLE>"; sub summary { my ($label,$grades)=@_; my %tables=("header"=>"","body"=>""); $tables{"header"}="<H2>$label</H2>"; foreach $key (keys %{$grades}) { $tables{"body"}.="<TR><TD>$key</TD><TD>$grades->{$key}</TD></TR>"; } return \%tables; } צריך להודות שדוגמא סופית זו דורשת גם קריאה שניה, או שלישית, או רביעית... מטרת התוכנית הזו להדפיס קוד HTML אשר מסכם את הציונים המוכלים בתוך האש ה grades%. ראשית ניצור האש רגיל, וסקלר המכיל תווית. עכשיו הדברים מסתבכים. קריאת ה print הראשונה קוראת לתת תוכנית summery&, ומעבירה אליה את ה label$ והפניה להאש grades%. תת התוכנית, בתגובה, יוצרת הפניה להאש התוצאות, כאשר אחד המפתחות בו הוא ה "header" (כותרת). לכן חשבו על תת התוכנית כהפניה אחת גדולה להאש, וככזו אנו מבצעים את ביטול ההפניה לקריאה אליה, על מנת לשלוף את הערך של מפתח ה "header". רעיון זהה עומד גם מאחורי הקריאה הבאה ל print. שוב, אנו מתייחסים כל תת התוכנית summary&, כהפניה אחת גדולה, בגלל אופי המידע המוחזר, ולפיכך אנו מבצעים ביטול הפניה למפתח ה "body". עתה נביט על תת התוכנית עצמה. היא מקבלת שני פרמטרים לתוך משתנה סקלרי ומשתנה הפניה, grades$, מקומיים. ההאש המקומי, table% נבנה על מנת להכיל את התוצאות, והערך למפתח ה "header" מושם בתוכו. לולאת foreach מתוחכמת נבנית על מנת לשלוף את המפתחות, ועוברת על כל מפתח בנפרד. לכל מפתח, נבנת שורת HTML בעזרת שימוש במפתח ובערך הצמוד עליו, המושגים ע"י ביטול ההפניה ל grades$ . ואלו רק שתי שורות קוד! הHTML שנבנה מוכנס לתוך הערך של מפתח ה "body" בהאש ה tables% המקומי שלנו. לבסוף, תת התוכנית מחזירה הפניה להאש זה - וזה מה שנותן לנו את האפשרות להתייחס לכל תת התוכנית שלנו כהפניה להאש - אפשרות הממומשת בהוראת ה print. הבא נרקוד, הפניה יקרה
|