switch משווה ערך אחד לרשימה של מקרים ומריצה את ההתאמה הראשונה. בניגוד ל-C, ל-Java ול-JavaScript, מקרה ב-Go לא נופל הלאה למקרה הבא, כך שאין break לשכוח.
המקרים נבדקים מלמעלה למטה, ורק המקרה המתאים הראשון רץ. default רץ כששום דבר לא מתאים; הוא אופציונלי ויכול להופיע בכל מקום ברשימה, אבל לפי המוסכמה הוא בא אחרון.
כמה ערכים לכל מקרה
case "sat", "sun": מתאים לכל אחד מהערכים. כך Go מבטאת את מה ש-C עושה עם מקרים ריקים מוערמים. כל טיפוס comparable עובד: מחרוזות, מספרים, runes, בוליאנים, מצביעים וטיפוסים עם שם כמו enums:
שני מקרים עם אותו ערך קבוע הם שגיאת הידור:
./main.go:10:7: duplicate case 1 (constant of type int) in expression switch
./main.go:8:7: previous case
Switch בלי תנאי
השמיטו את הביטוי וכל מקרה הופך לבדיקה בוליאנית. זו הצורה הנקייה יותר של Go לשרשרת ארוכה של if/else if:
switch { הוא קיצור של switch true {. מכיוון שהמקרה הראשון שמתקיים מנצח, הסדר חשוב: מגיעים ל-bmi < 25 רק כש-bmi < 18.5 היה false, כך שכל מקרה יכול להניח שהמקרים שלפניו נכשלו.
Switch עם פקודת אתחול
כמו if, switch יכולה להתחיל בפקודה קצרה. משתנים שמוצהרים שם תקפים רק בתוך ה-switch:
אפשר לשלב את פקודת האתחול גם עם switch בלי ביטוי: switch n := len(items); { case n == 0: ... }.
fallthrough
כשכן רוצים להמשיך למקרה הבא, כתבו fallthrough כפקודה האחרונה של מקרה. הוא מעביר את השליטה לגוף של המקרה הבא בלי להעריך את התנאי שלו:
רמה 2 מדפיסה write ואחר כך read, וצוברת הרשאות כלפי מטה. התנאים של המקרים הבאים לא נבדקים: אחרי fallthrough מ-case 2, case 1 רץ למרות ש-level הוא 2.
כללים ל-fallthrough:
- הוא חייב להיות הפקודה האחרונה במקרה.
- הוא לא יכול להופיע במקרה האחרון:
cannot fallthrough final case in switch. - הוא לא מותר ב-type switch.
בפועל fallthrough נדיר בקוד Go. כמה ערכים לכל מקרה מכסים את הצורך הנפוץ, וקריאות מפורשות לפונקציות בדרך כלל ברורות יותר משרשרת של fallthroughs.
break בתוך switch
break בתוך מקרה יוצא מה-switch. מקרים נגמרים מעצמם, כך שצריך אותו רק כדי לצאת ממקרה מוקדם. המלכודת היא switch בתוך לולאה:
בלי התווית loop, break מסיים את ה-switch והלולאה ממשיכה ל-"c". continue, לעומת זאת, תמיד מתייחס ללולאה העוטפת, כי switch היא לא לולאה.
Switch לפי טיפוסים
type switch מתפצל לפי הטיפוס הדינמי של ערך interface, בעזרת הצורה המיוחדת v.(type):
במקרה עם טיפוס יחיד, ל-x יש את הטיפוס הזה (len(x) עובד במקרה של string). במקרה שמפרט כמה טיפוסים, x שומר על טיפוס ה-interface. הדף על type assertions מכסה type switches ואת ה-assertion v.(T) לעומק.
מה ש-switch של Go עושה אחרת
| התנהגות | C, Java, JavaScript | Go |
|---|---|---|
| נפילה למקרה הבא | ברירת מחדל | רק עם fallthrough |
break בסוף כל מקרה | חובה | לא נחוץ |
| כמה ערכים לכל מקרה | מקרים ריקים מוערמים | case a, b, c: |
| ערכי מקרה | קבועים (בעיקר) | כל ביטוי, מוערך מלמעלה למטה |
| ערך ה-switch | טיפוסי מספרים שלמים (C) | כל טיפוס comparable |
| בלי ביטוי switch | לא מותר | switch { case cond: } |
ביטויי מקרה לא חייבים להיות קבועים. case limit(), max + 1: חוקי; הם מוערכים לפי הסדר עד שאחד מתאים, כך שביטויים מאוחרים יותר עשויים לא לרוץ אף פעם.
כיסוי מלא
Go לא בודקת ש-switch על enum מכסה כל ערך. הוסיפו default שרושם ללוג, מחזיר שגיאה או גורם ל-panic בערכים שלא ציפיתם להם, או השתמשו ב-linter בשם exhaustive (חלק מ-golangci-lint) כדי שמקרים חסרים ידווחו בזמן ה-build.
שאלות נפוצות
האם switch ב-Go נופלת הלאה למקרה הבא?
לא. מקרה ב-Go נגמר אוטומטית ב-case הבא; אף פעם לא כותבים break כדי לעצור אותו. אם רוצים שהביצוע ימשיך לגוף של המקרה הבא, כתבו fallthrough כפקודה האחרונה של המקרה. הוא קופץ ללא תנאי, בלי לבדוק את התנאי של המקרה הבא.
איך מתאימים כמה ערכים במקרה אחד ב-Go?
פרטו אותם מופרדים בפסיקים: case "sat", "sun":. המקרה רץ אם ערך ה-switch שווה לאחד מהם. זה מחליף את המקרים הריקים הנופלים הלאה שמערימים ב-C או ב-Java.
מה זה switch בלי תנאי ב-Go?
switch { case x < 0: ...; case x == 0: ...; default: ... }. כשאין ביטוי אחרי switch, כל מקרה הוא תנאי בוליאני והראשון שמתקיים רץ. זה התחליף האידיומטי לשרשרת ארוכה של if/else if.
מה break עושה בתוך switch ב-Go?
הוא מסיים את ה-switch, לא לולאת for שעוטפת אותה. לעיתים רחוקות צריך אותו, כי מקרים נגמרים מעצמם, אבל הוא מפתיע מי שכותב break בתוך switch שבתוך לולאה ומצפה לצאת מהלולאה. לשם כך השתמשו ב-break עם תווית או ב-return.