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 {}dajesyntax error: unexpected name x at end of statement, bowhilenie jest słowem kluczowym; kompilator czyta je jako zwykłą nazwę. - Nawiasy z przyzwyczajenia.
for (x < 5) {}się kompiluje, agofmtusuwa 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. Zadeklarujnprzed 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.