ProgrammazioneGo backend engineer

Spiega come funziona il meccanismo range in Go quando si lavora con map e slice. Quali sono le sottigliezze nell'uso delle variabili di ciclo e quali errori possono sorgere?

Supera i colloqui con l'assistente IA Hintsage

Risposta

Il ciclo for ... range consente di attraversare facilmente gli elementi di uno slice, di una mappa, di un array o di una stringa.

  • Per slice: ad ogni iterazione restituisce l'indice e una copia dell'elemento.
  • Per map: restituisce la chiave e una copia del valore.

Esempio:

s := []int{1, 2, 3} for i, v := range s { fmt.Println(i, v) } m := map[string]int{"a":1, "b":2} for k, v := range m { fmt.Println(k, v) }

Sottigliezza chiave: Le variabili i, v, k, ecc. vengono riutilizzate in tutte le iterazioni! Questo spesso diventa fonte di bug quando vengono passate per riferimento all'interno del ciclo o quando viene avviata una goroutine all'interno del range.

Domanda trabocchetto

Cosa succede se all'interno del range su uno slice avviate una goroutine catturando la variabile di iterazione? Come evitare l'errore?

Risposta: Si verifica un errore tipico: all'interno della goroutine vengono utilizzate le variabili del ciclo, che dopo il termine del ciclo avranno l'ultimo valore. Per evitare ciò, è necessario creare copie locali:

nums := []int{1, 2, 3} for _, v := range nums { go func(val int) { fmt.Println(val) }(v) }

Esempi di errori reali dovuti all'ignoranza delle sottigliezze


Storia

In un progetto si utilizzava range per popolare uno slice tramite diverse goroutine, dimenticando di fare copie delle variabili di ciclo. Tutte le goroutine hanno stampato lo stesso valore — l'ultimo dell'array, il che ha gravemente compromesso la logica di business.


Storia

Durante il range su una mappa, il riferimento al valore veniva salvato in un nuovo slice di puntatori. Di conseguenza, tutti gli elementi del nuovo slice facevano riferimento alla stessa variabile — quella utilizzata nel ciclo (copia del valore). Il bug si manifestava quando venivano aggiornate queste variabili al di fuori del ciclo (panic: indirizzo di memoria non valido o dati inaspettati).


Storia

In uno strumento interno, durante il range su stringhe avviavo gestori per sottostringhe significative, ma per ogni iterazione ottenevo un offset in byte, non in caratteri Unicode. Risultato: gestione errata delle stringhe Unicode, taglio errato dei caratteri.