Menu

if else ב-Golang: תחביר, פקודת אתחול ו-if err != nil

איך if, else if ו-else עובדים ב-Go: בלי סוגריים, עם סוגריים מסולסלים חובה, if עם פסוקית אתחול וה-scope שלה, הביטוי if err != nil, ו-return מוקדם במקום קינון עמוק.

בדף הזה יש עורכים שאפשר להריץ - לערוך, להריץ ולראות את הפלט מיד.

ל-if של Go אין סוגריים סביב התנאי, הוא תמיד דורש סוגריים מסולסלים, והוא יכול להתחיל בפקודה קצרה שמצהירה על משתנים שה-scope שלהם הוא ה-if.

התנאים נבדקים מלמעלה, והענף הראשון שמתקיים רץ. else if ו-else הם אופציונליים.

כללי תחביר

שלושה כללים שונים מ-C, מ-Java ומ-JavaScript:

  1. בלי סוגריים סביב התנאי. if (x > 5) מתקמפל, אבל gofmt מסיר את הסוגריים.
  2. סוגריים מסולסלים הם חובה, גם לפקודה אחת. אין if x > 5 return בלי סוגריים מסולסלים.
  3. else נמצא באותה שורה כמו הסוגר הסוגר. Go מוסיפה נקודה-פסיק אחרי } בסוף שורה, ולכן זה נכשל:
if x > 5 {
	fmt.Println("big")
}
else {
	fmt.Println("small")
}
syntax error: unexpected keyword else, expected }

כתבו } else { בשורה אחת.

התנאי חייב להיות bool. Go לא מתייחסת ל-0, ל-"" או ל-nil כאל false, ולכן if count {} ו-if name {} לא מתקמפלים. השוו במפורש: if count > 0, if name != "", if user != nil.

צרפו תנאים עם && (וגם), || (או) ו-! (לא). גם && וגם || עושים short-circuit, וזה הופך בדיקות nil לבטוחות:

if user != nil && user.IsAdmin() {
	// user.IsAdmin() is only called when user is not nil
}

if עם פקודת אתחול

if יכול להריץ פקודה קצרה אחת לפני התנאי, מופרדת בנקודה-פסיק. משתנים שהוצהרו בה נראים בכל ענף של אותו if, ובשום מקום אחריו:

התבנית הזאת שומרת משתנים קצרי חיים מחוץ ל-scope שמסביב. היא מופיעה כל הזמן עם חיפושים ב-map (v, ok := m[k]), עם type assertions (s, ok := v.(string)) ועם שגיאות.

הצד השני: אם צריך את הערך אחרי ה-if, הצהירו עליו לפניו. טעות נפוצה היא לשים תוצאה בפקודת האתחול ואז לנסות להשתמש בה בהמשך.

הביטוי if err != nil

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

שימו לב שאין else אחרי if err != nil { return ... }. בסגנון של Go מטפלים בשגיאה, חוזרים, ומשאירים את הזרימה הרגילה צמודה לשוליים. העמוד על טיפול בשגיאות מסביר על עטיפה ועל בדיקת טיפוסי שגיאות.

return מוקדם במקום קינון

בלוקי if מקוננים לעומק קשים לקריאה. הפכו את התנאים וחזרו מוקדם; כל בדיקה נקראת אז כשומר (guard):

// Nested
func canCheckout(u *User, cart *Cart) bool {
	if u != nil {
		if u.Verified {
			if len(cart.Items) > 0 {
				return true
			}
		}
	}
	return false
}

// Guards
func canCheckout(u *User, cart *Cart) bool {
	if u == nil || !u.Verified {
		return false
	}
	if len(cart.Items) == 0 {
		return false
	}
	return true
}

מתכנתי Go קוראים לזה לשמור את המסלול התקין מיושר לשוליים. linters כמו revive מסמנים else אחרי בלוק שמסתיים ב-return, כי ה-else מוסיף הזחה בלי סיבה.

if/else מול switch

שרשרת ארוכה של else if שבודקת ערך אחד מול כמה מקרים נקראת טוב יותר כ-switch. switch בלי ביטוי מחליף שרשרת if/else if של תנאים כלשהם:

switch {
case score >= 90:
	return "A"
case score >= 80:
	return "B"
default:
	return "F"
}

השתמשו ב-if לענף אחד או שניים, וב-switch כשיש שלושה ענפים או יותר.

אין אופרטור טרנרי

ב-Go אין cond ? a : b. בצעו השמה עם if:

label := "odd"
if n%2 == 0 {
	label = "even"
}

העמוד על האופרטור הטרנרי מסביר למה ומראה את החלופות.

טעויות נפוצות

  • הצללה עם :=. if x, err := f(); err == nil { ... } מצהיר על x חדש רק בשביל ה-if. x חיצוני לא מתעדכן.
  • השמה בתוך התנאי. if x = 5 {} היא שגיאת קומפילציה (cannot use assignment x = 5 as value), לא באג שקט כמו ב-C. השתמשו ב-==.
  • השוואת floats עם ==. if total == 0.3 נכשל לערכים מחושבים. השוו עם סבולת.
  • בדיקת השגיאה הלא נכונה. אחרי a, err := f() ו-b, err := g(), ודאו שכל if err != nil נמצא מיד אחרי הקריאה שלו.

שאלות נפוצות

איך כותבים if else ב-Go?

בלי סוגריים סביב התנאי, ותמיד עם סוגריים מסולסלים:

if x > 10 {
	fmt.Println("big")
} else if x > 5 {
	fmt.Println("medium")
} else {
	fmt.Println("small")
}

else חייב להיות באותה שורה כמו הסוגר הסוגר של הבלוק הקודם.

מה זה if עם פקודת אתחול ב-Go?

פקודה קצרה לפני התנאי, מופרדת בנקודה-פסיק: if n, err := strconv.Atoi(s); err != nil { ... }. משתנים שהוצהרו שם קיימים רק בתוך ה-if ובענפי ה-else if וה-else שלו, וכך הם לא דולפים לשאר הפונקציה.

אפשר לכתוב if בשורה אחת ב-Go?

לא בלי סוגריים מסולסלים. if ok return ו-if (ok) x = 1; הם שגיאות תחביר. הצורה הקצרה ביותר היא if ok { return }, ו-gofmt מעביר את הגוף לשורה משלו. ב-Go גם אין אופרטור טרנרי, כך שערך מותנה צריך if/else או פונקציית עזר קטנה.

למה Go משתמשת ב-if err != nil בכל מקום?

ב-Go אין exceptions. פונקציות שיכולות להיכשל מחזירות error כתוצאה האחרונה שלהן, והקוד הקורא בודק אותו מיד עם if err != nil. החזרה הזאת היא המחיר של כך שכל נקודת כישלון גלויה במקום שבו היא קורית.

איור של שפות התכנות ב-Coddy

ללמוד תכנות עם Coddy

להתחיל