היסודות
if ב-Zero נראה בערך כמו if בכל שפה אחרת ממשפחת C, עם הגבלה בולטת אחת: התנאי חייב להיות bool.
התנאי value == 42 הוא bool כי == בין שני ערכי i32 מחזיר bool. כל אחת משתי הזרועות מכילה בלוק של פקודות. אפשר פחות או יותר להשמיט זרוע, ה-else אופציונלי, אבל כששתיהן קיימות, שתיהן חייבות להיות בלוקים של { ... }.
הדרישה ל-bool
שפות מסוימות מאפשרות לכתוב if value { ... } ולהתייחס ל-0, ל-"" או ל-null כאל falsy. Zero לא. התנאי חייב להיות bool אמיתי.
let count = 0
if count { // שגיאת קומפילציה: מצופה bool, התקבל i32
// ...
}
if count == 0 { // OK
check world.out.write("nothing to do\n")
}
הסיבה זהה לזו שעוברת בכל שאר השפה: מפורש עדיף על מרומז. סוכן שקורא את הצורה השנייה יודע בדיוק מה נבדק. הצורה הראשונה משאירה את כללי ה-truthiness מרומזים, והם משתנים בין שפות: Zero בוחרת לוותר עליהם.
Else ו-Else-If
פסוקית else רצה כשהתנאי שקרי:
משרשרים תנאים עם else if:
if value < 0 {
check world.out.write("negative\n")
} else if value == 0 {
check world.out.write("zero\n")
} else {
check world.out.write("positive\n")
}
else if הוא פשוט else { if ... } בלי הסוגריים המסולסלים: אותה סמנטיקה, פחות הזחה. ה-else האחרון אופציונלי.
מאיפה מגיע התנאי
התנאי יכול להיות כל דבר שמחושב ל-bool:
- קישור מטיפוס
bool:if ok { ... }. - השוואה:
if value == 42 { ... },if x < y { ... }. - צירוף לוגי:
if a && b { ... },if pair.left == 1_u8 && pair.right == 2_u8 { ... }. - קריאה לפונקציה שמחזירה
bool:if isReady(world) { ... }.
קטע אמיתי מתוך הדוגמאות של השפה:
let pair: BytePair = Pair { left: 1_u8, right: 2_u8 }
if pair.left == 1_u8 && pair.right == 2_u8 {
check world.out.write("type alias ok\n")
} else {
check world.out.write("type alias broke\n")
}
&& מקצר את החישוב כמו שהייתם מצפים: אם האופרנד הראשון הוא false, האופרנד השני לא מחושב. אותו דבר עבור ||.
מתי להשתמש ב-match במקום
שרשראות if/else if מתאימות להחלטות של שניים או שלושה כיוונים, במיוחד כשלתנאים אין מבנה משותף. אבל כשמפצלים לפי הוריאנטים של טיפוס סכום, choice או enum, match הוא הכלי הנכון.
השוו:
// match: ממצה, נבדק על ידי הקומפיילר
match result {
.ok => value { check world.out.write("ok\n") }
.err => message { check world.out.write("err\n") }
}
לעומת:
// if/else על טיפוס סכום: ארוך יותר וקל יותר לטעות בו
if result.isOk() {
let value = result.unwrap()
check world.out.write("ok\n")
} else {
check world.out.write("err\n")
}
הצורה של match הופכת את ניתוח הוריאנטים למפורש, והקומפיילר יתלונן אם יתווסף בהמשך וריאנט ותשכחו לטפל בו. הצורה של if מעבירה בשקט כל מה שאינו ok לענף ה-else, כולל וריאנטים חדשים לגמרי שמעולם לא חשבתם עליהם.
כלל אצבע: if לבוליאנים, match לוריאנטים.
הערות סגנון
כמה מוסכמות קטנות שהופכות קוד לקל יותר לקריאה, גם לבני אדם וגם לסוכנים:
- תמיד עטפו את הגוף בסוגריים מסולסלים. גם גוף של שורה אחת נכנס ל-
{ ... }. אין צורה של פקודה בודדת בלי סוגריים. זה מכוון: כך ההזחה נשארת אמינה, ומוסר מקור נפוץ לבאגים במשפחת C. - שימו את הענף הנפוץ ביותר ראשון. קוראים (וסוכנים) סורקים מלמעלה למטה.
- העדיפו תנאים חיוביים כשהם ברורים באותה מידה.
if isReadyקל יותר למעקב מאשרif !notReady, כשכל השאר שווה.
הבא בתור: לולאות While
תנאים מחליטים מה לעשות; לולאות מחליטות כמה פעמים לעשות את זה. המסמך הבא מכסה את לולאות while של Zero, מבנה הלולאה של השלב המוקדם שהשפה מגיעה איתו.
שאלות נפוצות
איך משפטי if עובדים ב-Zero?
משתמשים ב-if condition { ... } עם פסוקית else { ... } אופציונלית. התנאי חייב להיות bool: Zero לא ממירה מספרים שלמים, מחרוזות או ערכים אחרים לבוליאני. דוגמה: if value == 42 { check world.out.write("yes\n") } else { check world.out.write("no\n") }.
האם יש ב-Zero אופרטור טרנרי?
Zero שומרת בכוונה על משטח קטן ומשתמשת בבלוקים של if / else במקום באופרטור טרנרי נפרד מהצורה condition ? a : b. הדוגמאות הרשמיות מעדיפות ענפים מפורשים גם במקרים קצרים. אם השפה שלכם תומכת ב-if כביטוי, צפו ש-Zero תנטה לכיוון הזה ולא תוסיף תחביר שני.
האם אפשר לשרשר if/else if ב-Zero?
כן. משרשרים תנאים על ידי כתיבת else if בין הענפים: if a { ... } else if b { ... } else { ... }. להסתעפות מורכבת יותר על choice או enum, השתמשו במקום זאת ב-match: הוא ממצה יותר, והקומפיילר בודק שטיפלתם בכל וריאנט.
למה Zero לא ממירה ערכים ל-bool?
פילוסופיית העיצוב של Zero היא 'הכול מפורש'. truthiness מרומזת, כלומר התייחסות ל-0, ל-"" או ל-null כאל false, היא מקור נפוץ לבאגים, וקשה לסוכן לחשוב עליה בדיוק. הדרישה ל-bool אמיתי הופכת את החלטת ההסתעפות לגלויה בקוד המקור וקלה יותר לאימות מכני.
מתי להשתמש ב-match במקום ב-if/else?
השתמשו ב-match כשאתם מפצלים לפי הוריאנטים של choice או enum. הקומפיילר יכול לוודא שכיסיתם כל מקרה, ושרשראות if/else if לא יכולות לעשות את זה. שמרו את if/else לפרדיקטים בוליאניים פשוטים: בדיקות שוויון, השוואות והסתעפויות קצרות לשני כיוונים.