Menu

Pętla while w Go (Golang): jak napisać while i do-while

Go nie ma słowa kluczowego while. Pętla for z samym warunkiem to while w Go, for bez warunku to pętla nieskończona, a do-while to pętla nieskończona ze sprawdzeniem na końcu.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

Go nie ma słowa kluczowego while. Napisz for, a po nim warunek, i masz pętlę while:

Warunek jest sprawdzany przed każdą iteracją, więc jeśli na starcie jest fałszywy, ciało nie wykona się ani razu. To dokładnie to samo co while (balance < 2000) w C, Javie czy JavaScripcie, tylko bez nawiasów i bez słowa kluczowego. Twórcy Go postawili na jedno słowo kluczowe dla wszystkich rodzajów pętli; wszystkie cztery formy znajdziesz na stronie o pętli for.

while(true): pętla nieskończona

Pomiń warunek całkowicie, a pętla będzie działać, dopóki coś w jej wnętrzu jej nie zakończy:

for { } to idiomatyczny zapis. for true { } też się kompiluje, ale wygląda jak nawyk przeniesiony z innego języka.

Pętlę nieskończoną kończą cztery rzeczy: break (wyjście z pętli), return (wyjście z funkcji), panic oraz os.Exit. Program, którego main tkwi w for {} bez żadnej z nich, działa, dopóki ktoś go nie zabije, i to jest dokładnie to, czego potrzebuje serwer albo worker.

do-while

Do-while wykonuje ciało raz, zanim sprawdzi warunek. Go nie ma do tego osobnej składni. Umieść sprawdzenie na końcu pętli nieskończonej:

Ciało wykona się co najmniej raz bez względu na wszystko, i to jest cecha, która definiuje do-while. Źródło losowości używa stałego ziarna, więc wynik jest taki sam przy każdym uruchomieniu; do prawdziwej losowości użyj rand.IntN bez źródła z ziarnem.

Druga forma zostawia warunek w nagłówku, wymuszając pierwsze przejście:

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

Działa, ale pętla nieskończona z break na końcu jest czytelniejsza i tak właśnie robi większość kodu w Go.

Czytanie do końca danych

Najczęstsza pętla while w prawdziwym kodzie Go czyta wejście, dopóki się nie skończy. bufio.Scanner jest do tego stworzony: Scan zwraca false na końcu wejścia albo przy błędzie, więc służy jako warunek pętli:

Zamień strings.NewReader(input) na os.Stdin, a ta sama pętla będzie czytać dane od użytkownika linia po linii. Po pętli sprawdź scanner.Err(): to, że Scan zwraca false, nie mówi, czy wejście skończyło się normalnie, czy wystąpił błąd.

break i continue

Oba działają w każdej formie for:

W pętli z samym warunkiem continue skacze prosto do warunku. To ułatwia subtelny błąd: jeśli licznik jest aktualizowany na dole ciała, continue położone wyżej pomija aktualizację i pętla nigdy się nie kończy. Aktualizuj licznik na górze, jak powyżej, albo użyj for z trzema klauzulami, w którym instrukcja post wykonuje się nawet po continue.

Czekanie na coś

Pętla, która czeka na warunek, powinna się blokować albo usypiać, a nie kręcić się w miejscu:

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

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

Odpytywanie zwykłej zmiennej, do której pisze inna goroutine, to w dodatku wyścig danych (data race). Między goroutines czekaj na kanale, na sync.WaitGroup albo sync.Cond, albo użyj select z timerem. Przy pętlach ponawiania z limitem wybierz for z licznikiem, żeby pętla nie mogła działać w nieskończoność:

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

Częste błędy

  • Brak zmiany zmiennej z warunku. for i < 10 { fmt.Println(i) } nigdy się nie kończy. Każda pętla while potrzebuje w ciele czegoś, co przybliża ją do wyjścia.
  • Pisanie while. while x < 5 {} daje syntax error: unexpected name x at end of statement, bo while nie jest słowem kluczowym; kompilator czyta je jako zwykłą nazwę.
  • Nawiasy z przyzwyczajenia. for (x < 5) {} się kompiluje, a gofmt usuwa nawiasy.
  • Deklarowanie zmiennej w pętli. for n := 10; n > 0 {} to błąd składni; pętla z klauzulą inicjalizacji potrzebuje wszystkich trzech klauzul. Zadeklaruj n przed pętlą albo napisz pełną formę z trzema klauzulami.

Najczęściej zadawane pytania

Czy Go ma pętlę while?

Nie jako słowo kluczowe. Go używa for do wszystkich pętli, a for z samym warunkiem to dokładnie pętla while:

for count < 10 {
	count++
}

Warunek jest sprawdzany przed każdą iteracją, tak samo jak while (count < 10) w C albo Javie.

Jak napisać while(true) w Go?

Napisz for bez niczego dalej: for { ... }. Pętla działa, dopóki nie zakończy jej break, return, panic albo os.Exit. for true { ... } też się kompiluje, ale idiomatyczną formą jest for { }.

Jak napisać pętlę do-while w Go?

Użyj pętli nieskończonej i umieść sprawdzenie warunku na końcu ciała:

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

Ciało zawsze wykonuje się raz, zanim warunek zostanie sprawdzony, i właśnie to oznacza do-while.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ