In Go erhalten Variablen, die ohne expliziten Initialisierer deklariert werden, automatisch sogenannte Zero Values (null-Werte), die für verschiedene Typen unterschiedlich sind:
int — 0bool — falsestring — ""Das ist praktisch (keine Müll in der Speichernutzung), kann aber gefährlich sein: Bei einigen Typen, wie Slices und Maps, kann die Arbeit mit nil-Werten zu Paniken oder Bugs führen.
Beispiel:
var m map[string]int m["key"] = 1 // panic: assignment to entry in nil map var s []int fmt.Println(s, s == nil) // [] true (kann Elemente hinzufügen, aber nicht auf Indizes zugreifen)
Worin besteht der Unterschied zwischen einem nil-Wert eines Slices und einem nil-Wert einer Map/eines Channels, und zu welchen Bugs führt das?
Die richtige Antwort: Ein Slice mit nil-Wert kann sicher an Funktionen übergeben und in append und range verwendet werden — das ist sicher, aber die Arbeit mit einer nil-Map führt zu einer Panik beim Schreibversuch (aber das Lesen ist erlaubt und gibt den Zero Value zurück).
Beispiel:
var m map[string]int fmt.Println(m["no_key"]) // 0 — sicher m["key"] = 1 // panic! var s []int s = append(s, 42) // ok
Geschichte
Beschreibung: In einem großen Projekt wurden nicht initialisierte Maps zur Aggregation von Daten verwendet. Bei der ersten Speicherung stürzte die Anwendung ständig mit Panic ab. Das Problem wurde in der Produktion entdeckt, als neue Statistiken eingeführt wurden.
Geschichte
Beschreibung: Ein Dienst serialisierte ein nicht initialisiertes Slice und sendete es als JSON in der API-Antwort. Anstelle von
[]erhielten die Kundennull— wir mussten das Schema auf der Frontend-Seite ändern, um beide Varianten zu handhaben.
Geschichte
Beschreibung: In einem Caching-Modul wurden nil Maps fälschlicherweise mit leeren Maps verglichen, wodurch nicht korrekt festgestellt wurde, ob Elemente vorhanden sind. Dies führte zu unnötigen Datenbankzugriffen und verringerte die Leistung.