In Go, il tipo struct{} rappresenta una struttura senza campi e occupa 0 byte di memoria. Questa è una caratteristica preziosa, utilizzata per ridurre il consumo di risorse nei casi in cui è importante il fatto che qualcosa esista, ma non sono necessari dati — ad esempio, nell'implementazione di insiemi (set), strutture di segnalazione o canali per eventi.
Esempio di uso per un insieme:
mySet := make(map[string]struct{}) mySet["foo"] = struct{}{} if _, ok := mySet["foo"]; ok { fmt.Println("foo è presente in mySet") }
struct{} è utilizzato come valore per indicare la presenza di una chiave.map[string]bool, la variante con struct{} è più efficiente in termini di memoria.Canali per la segnalazione:
done := make(chan struct{}) // La goroutine attende un segnale di completamento <-done
Qual è la differenza tra map[string]struct{} e map[string]bool nella realizzazione di un insieme? Perché map[string]struct{} è preferibile e ha degli svantaggi?
Risposta:
map[string]struct{} utilizza 0 byte per valore, la variante più compatta — questo fa risparmiare memoria, specialmente con una grande quantità di dati.map[string]bool richiede 1 byte per valore (internamente può comunque occupare più memoria a causa dell'allineamento).map[string]struct{}: non è possibile ottenere rapidamente un elenco di tutti i valori contrassegnati come true, se mai fosse necessario un valore booleano. Bisogna comunque iterare sulle chiavi.Esempio:
set := make(map[string]struct{}) set["Alice"] = struct{}{} _, exists := set["Alice"] // true flags := make(map[string]bool) flags["Alice"] = true _, exists := flags["Alice"] // true
Storia
In un progetto per memorizzare identificatori unici, è stato utilizzato map[string]bool, il che ha portato, con l'aumento dei dati, a un significativo incremento del consumo di memoria — centinaia di megabyte rispetto alla variante con map[string]struct{}. La transizione a struct{} ha ridotto il consumo di memoria di oltre la metà.
Storia
Un principiante segnalava il completamento di una goroutine tramite
chan bool. Con un gran numero di goroutine, la trasmissione del valore è risultata eccessiva: non veniva mai analizzato se fosse arrivatotrueofalse. Sostituire conchan struct{}ha rivelato un'imprecisione architetturale e ha semplificato il codice.
Storia
In una libreria si stava creando un insieme tramite map, dove come valore veniva utilizzato string. Questo occupava troppa memoria. Dopo il Code Review, è stato convertito in map[tipo]struct{}. L'errore è stato individuato dopo l'analisi del profilo di memoria durante i test di carico, quando l'applicazione è andata in OOM.