exists#
לבדוק האם אלמנט של האש או מערך, או תת־שגרה בעלת שם, נוכח - מבלי ליצור אותו ומבלי לדאוג למה שהוא מחזיק.
exists שואל שאלה מבנית: האם יש רשומה במיקום הזה? הוא אינו שואל מהו הערך של הרשומה. רשומה שערכה הוא undef עדיין קיימת. רשומה שלעולם לא הושמה לה ערך אינה קיימת - חיפוש שלה בקריאה פשוטה היה מחזיר undef, אבל exists מבחין בין שני המקרים.
תקציר#
exists $hash{KEY}
exists $array[INDEX]
exists &subroutine
exists $ref->{A}{B} # autovivifies $ref->{A}!
מה מקבלים בחזרה#
בוליאני: 1 (סקלר אמת) אם האלמנט או תת־השגרה נוכחים, המחרוזת הריקה "" (סקלר שקר) אם לא. התוצאה היא תמיד סקלר פשוט - אין וריאנט של הקשר רשימה.
my %h = (a => undef);
exists $h{a}; # 1 (key exists)
defined $h{a}; # "" (value is undef)
exists $h{b}; # "" (key does not exist)
exists אינו defined#
השניים עונים על שאלות שונות והם חלוקים בדיוק כאשר רשומה קיימת מחזיקה undef:
מצב |
| קריאה פשוטה | |
|---|---|---|---|
לעולם לא הושמה לו ערך | שקר | שקר | |
הושמה לו | אמת | שקר | |
הושמה לו ערך אחר כלשהו | אמת | אמת | הערך הזה |
יש להשתמש ב־exists כאשר צריך לדעת האם מפתח הוצב במבנה - לדוגמה האש אפשרויות שבו מפתח חשוף משמעו ״הקורא הצטרף, הערך לא משנה.״ יש להשתמש ב־defined כאשר צריך לדעת האם ערך הוא שמיש.
דוגמאות#
בדיקת מפתח האש. מבנה האש האפשרויות הקלאסי - נוכחות, לא אמת:
sub configure {
my %opt = @_;
my $verbose = exists $opt{verbose}; # caller passed verbose => anything
my $color = $opt{color} // "auto"; # caller-supplied or default
...
}
הבחנה בין ״חסר״ ל־״נוכח אך undef״:
my %cache = (user_42 => undef); # cached: "we looked, nothing there"
if (exists $cache{user_42}) {
# hit - even though the value is undef, we already did the lookup
} else {
# miss - have to query the database
}
בדיקת מערך דליל. מחיקת אלמנט מערך משאירה חור ש־exists מדווח כשקר:
my @a = (10, 20, 30);
delete $a[1];
exists $a[0]; # 1
exists $a[1]; # "" (hole)
exists $a[2]; # 1
exists $a[99]; # "" (past the end)
קיום תת־שגרה. אמת ברגע שתת־השגרה הוצהרה, גם אם הגוף הוא הצהרה מקדימה ללא הגדרה עדיין:
sub later; # forward declaration
exists &later; # 1
defined &later; # "" (no body yet)
sub later { 42 }
defined &later; # 1
מבנה מקונן - הדרך הבטוחה. יש לבדוק כל רמה לפני שיורדים, מכיוון שלצורת שרשרת החצים יש תופעת לוואי (ראו מקרי קצה):
if (exists $tree{users}
&& exists $tree{users}{$id}
&& exists $tree{users}{$id}{email}) {
send_mail($tree{users}{$id}{email});
}
מקרי קצה#
Autovivification של רמות ביניים. זוהי המלכודת החשובה ביותר היחידה.
exists $ref->{A}{B}{C}בודק את המפתח הפנימי ביותר, אך הערכת הביטוי מבצעת autovivify לכל האש ביניים -$ref->{A}ו־$ref->{A}{B}קופצים לקיום כהאשים ריקים גם כאשר בדיקת ה־existsמחזירה שקר:my %h; exists $h{a}{b}{c}; # returns "" (false) exists $h{a}; # now returns 1 - $h{a} was created! exists $h{a}{b}; # likewise - now an empty hash
האלמנט הפנימי ביותר הוא היחיד שאינו מבצע autovivify. אותו דבר קורה דרך הפניות:
exists $ref->{A}על$refשהוא undef מחיה את$refלהפניית האש. אם נדרש לבחון מבנה עמוק מבלי לשנותו, יש לעבור עליו רמה אחת בכל פעם עםexistsבכל שלב, או להשתמש בעוזר ייעודי כמו סמנטיקת [Data::Diver] (תחום פרגמהeval/no autovivificationמשורשר).existsעל מפתח עם ערךundefהוא אמת. זהו ההבדל המגדיר מ־defined.deleteמסיר גם את המפתח וגם את הערך; השמתundefשומרת את המפתח.גבולות מערך.
exists $a[$i]הוא שקר כאשר$iמעבר לסוף המערך או כאשר החריץdeleteed באמצע המערך. אינדקסים שליליים נספרים מהסוף:exists $a[-1]בודק את האלמנט האחרון אם המערך לא־ריק.existsעל מערך אינו מומלץ ב־upstream. הרעיון של מחיקת אלמנט מערך אינו נקי מבחינה רעיונית -delete $a[1]משאיר חור במקום להזיז. רוב הקוד שפונה ל־exists $a[$i]משרת טוב יותר על־ידי בדיקת גבולות ($i <= $#a) או על־ידי שימוש בהאש.exists &sub()היא שגיאת תחביר. הארגומנט חייב לנקוב בשם תת־שגרה, לא לקרוא לאחת.exists &subשואל ״האםsubהוצהרה?״;exists &sub()היה אומר ״האם ערך ההחזרה של קריאה ל־subקיים?״, שזה חסר משמעות.AUTOLOADאינו נספר.exists &subהוא שקר עבור תת־שגרה שהייתה קופצת לקיום דרךAUTOLOADבקריאה הראשונה.existsכושל אינו מבטיח לכן שקריאה הייתה נכשלת.משתנים קשורים (tied). עבור האשים ומערכים קשורים,
existsקורא למתודהEXISTSעל העצם הקשור. מימוש ה־tie מחליט מה משמעות ״קיום״ - tie מסוגDBMבודק את הרשומה על הדיסק, tie עצלן עשוי לממש את הרשומה. ראוperltie.הארגומנט חייב להיות ביטוי lvalue שהפעולה הסופית שלו היא חיפוש מפתח או אינדקס, או שם תת־שגרה.
exists func(),exists $scalar,exists @array,exists %hashכולם שגיאות. רק גישה לאלמנט ו־&subמתקבלים.
הבדלים מ־upstream#
תואם מלא ל־upstream Perl 5.42.
ראו גם#
defined- שואל האם הערך שמיש, לא האם המפתח נוכח; נבדל מ־existsרק כאשר הערך המאוחסן הואundefdelete- מסיר רשומה כך ש־existsעליה הופך לשקר; המקבילה שלexistseach- עובר על זוגות מפתח/ערך של האש; מבקר רק במפתחות שעבורםexistsהוא אמתkeys- מחזיר את רשימת המפתחות הקיימים;exists $h{$k}שקול לשאלה האם$kנמצא ביןkeys %h, אך O(1) במקום O(n)ref- מסווג למה הפניה מצביעה; שימושי לפניexistsעל$ref->{...}אם אינך בטוח ש־$refהוא הפניית האשscalar- לאלץ הקשר סקלרי; יש לשים לב ש־existsהוא כבר רק־סקלרי ואינו זקוק לו