Hintergrund:
Go hat standardmäßig keine Set-Struktur, aber oft gibt es die Aufgabe, mit einzigartigen Elementen zu arbeiten. Eine optimale Struktur ist map[string]struct{}, wobei der Schlüssel das Element ist und die leere Struktur als „Präsenzmarkierung“ dient. Dies ist ein gängiges Muster für einen schnellen Mitgliedschaftstest.
Problem:
Der Mangel an einem eingebauten Set führt dazu, dass es Anfängern schwerfällt, einzigartige Sammlungen richtig zu implementieren. Außerdem muss man verstehen, warum struct{} effizienter ist als bool oder int als Wert.
Lösung:
Zur Implementierung eines Sets in Go verwendet man map[string]struct{}. Die leere Struktur struct{} benötigt keinen Speicher (zero-sized), und map bietet schnellen Zugriff. Beispiel:
set := make(map[string]struct{}) set["foo"] = struct{}{} if _, ok := set["foo"]; ok { fmt.Println("Present") } delete(set, "foo")
Wesentliche Merkmale:
Warum kann man nicht slice/Array als Wert verwenden?
slice/Array für Set bieten keine konstante Zeit für die Suche nach einem Element — man müsste alle Werte durchlaufen, was langsam ist.
Was unterscheidet map[string]struct{} von map[string]bool?
map[string]bool benötigt mehr Speicher: Für jeden Schlüssel wird ein bool gespeichert, während struct{} einen leeren Typ hat, der nichts allokiert.
set := map[string]bool{"foo": true}
Kann man int anstelle von struct{} verwenden?
Man kann, aber int benötigt immer Speicher. struct{} ist universell: Wenn nur eine „Marker“-Rolle (Präsenz) benötigt wird, ist es besser.
set := map[string]int{"foo": 1} // aber speichert (Schlüssel -> Zahl)
Wegen Unkenntnis wurde map[string]bool für ein Set einzigartiger IP-Adressen verwendet. Infolgedessen stieg der Speicherverbrauch bei Millionen von Adressen im Vergleich zu struct{} um das Doppelte.
Vorteile:
Nachteile:
In einem Projekt wurde für die Speicherung einzigartiger E-Mails map[string]struct{} verwendet. Die Last wurde verringert, es arbeitete schneller, der Speicherverbrauch für Werte war minimal.
Vorteile:
Nachteile: