In Go, le variabili dichiarate senza un inizializzatore esplicito ricevono automaticamente quelli che sono chiamati valori zero (zero values), che variano a seconda dei tipi:
int — 0bool — falsestring — ""Questo è comodo (assenza di spazzatura nella memoria), ma può essere pericoloso: per alcuni tipi, ad esempio slice e mappe, lavorare con un valore nil può portare a panico o bug.
Esempio:
var m map[string]int m["key"] = 1 // panic: assignment to entry in nil map var s []int fmt.Println(s, s == nil) // [] true (possiamo aggiungere elementi, ma non possiamo accedere per indice)
Come si differenzia un valore nil di uno slice da un valore nil di una mappa/canale, e quali bug può causare?
Risposta corretta: Un slice con valore nil può essere passato a funzioni, utilizzato in append e range — è sicuro, ma lavorare con una mappa nil porterà a un panico quando si tenterà di scrivere (ma la lettura è consentita e restituirà il valore zero).
Esempio:
var m map[string]int fmt.Println(m["no_key"]) // 0 — sicuro m["key"] = 1 // panic! var s []int s = append(s, 42) // ok
Storia
Descrizione: In un grande progetto venivano utilizzate mappe non inizializzate per l'aggregazione dei dati. Alla prima scrittura, l'applicazione andava in panico. Il problema è emerso in produzione, quando è stata introdotta una nuova statistica.
Storia
Descrizione: Un servizio serializzava uno slice non inizializzato, inviandolo come JSON nella risposta API. Invece di
[], i clienti ricevevanonull— è stato necessario modificare lo schema front-end per gestire entrambe le varianti.
Storia
Descrizione: In un modulo di caching comparavano erroneamente una mappa nil con una mappa vuota e per questo motivo determinavano in modo errato: se ci sono elementi. Questo portava a chiamate superflue al database, riducendo le prestazioni.