Go non ha la parola chiave while. Scrivi for seguito da una condizione e hai già un ciclo while:
La condizione viene controllata prima di ogni iterazione, quindi se è falsa fin dall'inizio il corpo non viene mai eseguito. È identico a while (balance < 2000) in C, Java o JavaScript, senza le parentesi e senza la parola chiave. I progettisti di Go hanno scelto un'unica parola chiave per ogni forma di ciclo; consulta la pagina del ciclo for per vedere tutte e quattro le forme.
while(true): il ciclo infinito
Se ometti del tutto la condizione, il ciclo continua finché qualcosa al suo interno non lo termina:
for { } è la forma idiomatica. Anche for true { } compila, ma sembra scritto da qualcuno che viene da un altro linguaggio.
Quattro cose terminano un ciclo infinito: break (esce dal ciclo), return (esce dalla funzione), un panic e os.Exit. Un programma il cui main resta in for {} senza nessuna di queste gira finché qualcuno non lo termina, ed è proprio il comportamento giusto per un server o un worker.
do-while
Un do-while esegue il corpo una volta prima di controllare la condizione. Go non ha una sintassi dedicata. Metti il controllo alla fine di un ciclo infinito:
Il corpo viene eseguito almeno una volta in ogni caso, ed è questa la proprietà che definisce un do-while. La sorgente casuale usa un seed fisso, così l'output è lo stesso a ogni esecuzione; usa rand.IntN senza una sorgente con seed per avere una vera casualità.
Una seconda forma mantiene la condizione nell'intestazione forzando il primo passaggio:
for first := true; first || condition(); first = false {
// body
}
Funziona, ma il ciclo infinito con un break alla fine è più leggibile, ed è ciò che fa la maggior parte del codice Go.
Leggere fino alla fine
Il ciclo while più comune nel codice Go reale legge l'input finché non finisce. bufio.Scanner è pensato proprio per questo: Scan restituisce false alla fine dell'input o in caso di errore, quindi fa da condizione del ciclo:
Sostituisci strings.NewReader(input) con os.Stdin e lo stesso ciclo legge l'input dell'utente riga per riga. Controlla scanner.Err() dopo il ciclo: il fatto che Scan restituisca false non ti dice se l'input è finito normalmente o se c'è stato un errore.
break e continue
Funzionano entrambi in ogni forma di for:
In un ciclo con la sola condizione, continue salta direttamente alla condizione. Questo rende facile un bug subdolo: se il contatore viene aggiornato in fondo al corpo, un continue posto prima salta l'aggiornamento e il ciclo non termina mai. Aggiorna il contatore all'inizio, come sopra, oppure usa un for a tre clausole, la cui istruzione post viene eseguita anche dopo continue.
Aspettare che succeda qualcosa
Un ciclo che aspetta una condizione dovrebbe bloccarsi o dormire, non girare a vuoto:
// Wrong: burns a CPU core while waiting
for !ready {
}
// Better: poll with a delay
for !isReady() {
time.Sleep(100 * time.Millisecond)
}
Interrogare una normale variabile scritta da un'altra goroutine è anche una data race. Tra goroutine, aspetta su un channel, un sync.WaitGroup o un sync.Cond, oppure usa select con un timer. Per i cicli di retry con un limite, preferisci un for con contatore, così il ciclo non può girare per sempre:
for attempt := 1; attempt <= 5; attempt++ {
if err := connect(); err == nil {
break
}
time.Sleep(time.Duration(attempt) * 200 * time.Millisecond)
}
Errori comuni
- Dimenticare di cambiare la variabile della condizione.
for i < 10 { fmt.Println(i) }non termina mai. Ogni ciclo while ha bisogno di qualcosa nel corpo che lo avvicini all'uscita. - Scrivere
while.while x < 5 {}dàsyntax error: unexpected name x at end of statement, perchéwhilenon è una parola chiave; il compilatore lo legge come un nome qualsiasi. - Parentesi per abitudine.
for (x < 5) {}compila, egofmtrimuove le parentesi. - Dichiarare la variabile nel ciclo.
for n := 10; n > 0 {}è un errore di sintassi; un ciclo con una clausola di inizializzazione ha bisogno di tutte e tre le clausole. Dichiaranprima del ciclo, oppure scrivi la forma completa a tre clausole.
Domande frequenti
Go ha un ciclo while?
Non come parola chiave. Go usa for per tutti i cicli, e un for con la sola condizione è esattamente un ciclo while:
for count < 10 {
count++
}
La condizione viene controllata prima di ogni iterazione, proprio come while (count < 10) in C o Java.
Come scrivo while(true) in Go?
Scrivi for senza niente dopo: for { ... }. Si ripete finché non lo termina un break, un return, un panic o os.Exit. Anche for true { ... } compila, ma for { } è la forma idiomatica.
Come scrivo un ciclo do-while in Go?
Usa un ciclo infinito e metti il controllo della condizione alla fine del corpo:
for {
// body runs at least once
if !condition {
break
}
}
Il corpo viene sempre eseguito una volta prima che la condizione venga verificata, ed è proprio questo il significato di do-while.