Menu

לולאת while ב-Golang: איך כותבים while ו-do-while ב-Go

ב-Go אין מילת מפתח while. לולאת for עם תנאי בלבד היא לולאת ה-while של Go, for בלי תנאי היא לולאה אינסופית, ו-do-while היא לולאה אינסופית שהבדיקה שלה נמצאת בסוף.

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

ב-Go אין מילת מפתח while. כתבו for ואחריו תנאי, וקיבלתם לולאת while:

התנאי נבדק לפני כל איטרציה, כך שאם הוא שקרי כבר בהתחלה, גוף הלולאה לא רץ אף פעם. זה זהה ל-while (balance < 2000) ב-C, ב-Java או ב-JavaScript, רק בלי הסוגריים ובלי מילת המפתח. המתכננים של Go בחרו במילת מפתח אחת לכל צורות הלולאה; בעמוד של לולאת for תמצאו את כל ארבע הצורות.

while(true): הלולאה האינסופית

השמיטו את התנאי לגמרי, והלולאה תרוץ עד שמשהו בתוכה יעצור אותה:

for { } היא הכתיבה האידיומטית. גם for true { } מתקמפל, אבל הוא נקרא כאילו הכותב הגיע משפה אחרת.

ארבעה דברים עוצרים לולאה אינסופית: break (יוצא מהלולאה), return (יוצא מהפונקציה), panic ו-os.Exit. תוכנית שה-main שלה יושב בתוך for {} בלי אף אחד מאלה רצה עד שמישהו הורג אותה, וזה בדיוק מה שצריך בשרת או ב-worker.

do-while

do-while מריצה את גוף הלולאה פעם אחת לפני שהיא בודקת את התנאי. ל-Go אין תחביר ייעודי לכך. שימו את הבדיקה בסוף לולאה אינסופית:

גוף הלולאה רץ לפחות פעם אחת בכל מקרה, וזו התכונה שמגדירה do-while. מקור האקראיות משתמש ב-seed קבוע, כך שהפלט זהה בכל הרצה; לאקראיות אמיתית השתמשו ב-rand.IntN בלי מקור עם seed.

צורה שנייה משאירה את התנאי בכותרת הלולאה בכך שהיא מכריחה את המעבר הראשון:

for first := true; first || condition(); first = false {
	// body
}

זה עובד, אבל הלולאה האינסופית עם break בסוף קריאה יותר, וזה מה שרוב קוד ה-Go עושה.

קריאה עד הסוף

לולאת ה-while הנפוצה ביותר בקוד Go אמיתי קוראת קלט עד שהוא נגמר. bufio.Scanner נבנה בדיוק בשביל זה: Scan מחזירה false בסוף הקלט או כשיש שגיאה, ולכן היא משמשת כתנאי הלולאה:

החליפו את strings.NewReader(input) ב-os.Stdin, ואותה לולאה תקרא את הקלט של המשתמש שורה אחר שורה. בדקו את scanner.Err() אחרי הלולאה: העובדה ש-Scan החזירה false לא אומרת אם הקלט הסתיים כרגיל או נכשל.

break ו-continue

שתיהן עובדות בכל הצורות של for:

בלולאה עם תנאי בלבד, continue קופצת ישר לתנאי. זה מקל על באג עדין: אם המונה מתעדכן בסוף גוף הלולאה, continue שנמצאת לפניו מדלגת על העדכון, והלולאה לא נגמרת לעולם. עדכנו את המונה בהתחלה, כמו בדוגמה, או השתמשו ב-for עם שלושה חלקים, שבה פקודת ה-post רצה גם אחרי continue.

המתנה למשהו

לולאה שמחכה לתנאי צריכה להיחסם או לישון, לא להסתובב על ריק:

// Wrong: burns a CPU core while waiting
for !ready {
}

// Better: poll with a delay
for !isReady() {
	time.Sleep(100 * time.Millisecond)
}

דגימה חוזרת של משתנה רגיל ש-goroutine אחרת כותבת אליו היא גם data race. בין goroutines, חכו על channel, על sync.WaitGroup או על sync.Cond, או השתמשו ב-select עם טיימר. ללולאות ניסיון חוזר עם הגבלה, העדיפו for עם מונה, כדי שהלולאה לא תוכל לרוץ לנצח:

for attempt := 1; attempt <= 5; attempt++ {
	if err := connect(); err == nil {
		break
	}
	time.Sleep(time.Duration(attempt) * 200 * time.Millisecond)
}

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

  • לשכוח לשנות את משתנה התנאי. for i < 10 { fmt.Println(i) } לא נגמרת לעולם. כל לולאת while צריכה משהו בגוף הלולאה שמקרב אותה ליציאה.
  • לכתוב while. while x < 5 {} נותן syntax error: unexpected name x at end of statement, כי while אינה מילת מפתח; הקומפיילר קורא אותה כשם רגיל.
  • סוגריים מתוך הרגל. for (x < 5) {} מתקמפל, ו-gofmt מסיר את הסוגריים.
  • להצהיר על המשתנה בתוך הלולאה. for n := 10; n > 0 {} היא שגיאת תחביר; לולאה עם פסוקית אתחול צריכה את כל שלושת החלקים. הצהירו על n לפני הלולאה, או כתבו את הצורה המלאה עם שלושה חלקים.

שאלות נפוצות

האם יש ב-Go לולאת while?

לא כמילת מפתח. Go משתמשת ב-for לכל הלולאות, ו-for עם תנאי בלבד היא בדיוק לולאת while:

for count < 10 {
	count++
}

התנאי נבדק לפני כל איטרציה, בדיוק כמו while (count < 10) ב-C או ב-Java.

איך כותבים while(true) ב-Go?

כותבים for בלי שום דבר אחריו: for { ... }. הלולאה חוזרת עד ש-break, return, panic או os.Exit עוצרים אותה. גם for true { ... } מתקמפל, אבל for { } הוא הצורה האידיומטית.

איך כותבים לולאת do-while ב-Go?

משתמשים בלולאה אינסופית ושמים את בדיקת התנאי בסוף גוף הלולאה:

for {
	// body runs at least once
	if !condition {
		break
	}
}

גוף הלולאה תמיד רץ פעם אחת לפני שהתנאי נבדק, וזו בדיוק המשמעות של do-while.

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

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

להתחיל