Menu

Ciclo while in Golang: come scrivere while e do-while in Go

Go non ha la parola chiave while. Un ciclo for con la sola condizione è il while di Go, un for senza condizione è un ciclo infinito e un do-while è un ciclo infinito con il controllo alla fine.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

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é while non è una parola chiave; il compilatore lo legge come un nome qualsiasi.
  • Parentesi per abitudine. for (x < 5) {} compila, e gofmt rimuove 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. Dichiara n prima 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.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA