Storia della domanda:
Go di default non ha una struttura Set, ma spesso si presenta la necessità di lavorare con elementi unici. La struttura ottimale è il map[string]struct{}, dove la chiave è l'elemento e la struttura vuota funge da "etichetta di presenza". Questo è un pattern comune per test di appartenenza rapidi.
Problema:
La mancanza di un Set incorporato porta i neofiti a trovare difficile implementare correttamente collezioni uniche. È inoltre necessario capire perché struct{} sia più efficiente di bool o int come valore.
Soluzione:
Per implementare un Set in Go si utilizza map[string]struct{}. La struttura vuota struct{} non richiede memoria (zero-sized), mentre la map fornisce un accesso veloce. Esempio:
set := make(map[string]struct{}) set["foo"] = struct{}{} if _, ok := set["foo"]; ok { fmt.Println("Presente") } delete(set, "foo")
Caratteristiche principali:
Perché non si può usare slice/array come valore?
slice/array per set non forniscono tempo di ricerca costante — bisognerebbe scorrere tutti i valori, il che è lento.
Qual è la differenza tra map[string]struct{} e map[string]bool?
map[string]bool occupa più memoria: per ogni chiave memorizza un bool, mentre struct{} è un tipo vuoto che non alloca nulla.
set := map[string]bool{"foo": true}
Si può usare int invece di struct{}?
Si può, ma int occupa sempre memoria. struct{} è universale: se è necessaria solo la funzione di "etichetta" (presenza), è migliore.
set := map[string]int{"foo": 1} // ma memorizza (chiave -> numero)
A causa dell'ignoranza è stato assegnato map[string]bool per un insieme di indirizzi IP unici. Di conseguenza, con milioni di indirizzi, l'uso di memoria è raddoppiato rispetto a struct{}.
Pro:
Contro:
Nel progetto per memorizzare email uniche è stato usato map[string]struct{}. Il carico è diminuito, ha lavorato più velocemente, la memoria quasi non è stata spesa per i valori.
Pro:
Contro: