En Go, le type struct{} représente une structure sans champs et occupe 0 octet de mémoire. C'est une caractéristique précieuse utilisée pour minimiser la consommation de ressources dans les cas où la présence de quelque chose est importante, mais où les données ne le sont pas — par exemple, dans la mise en œuvre d'ensembles (set), de structures de signalisation ou de canaux pour les événements.
Exemple d'utilisation pour un ensemble :
mySet := make(map[string]struct{}) mySet["foo"] = struct{}{} if _, ok := mySet["foo"]; ok { fmt.Println("foo est présent dans mySet") }
struct{} est utilisé comme valeur pour indiquer la présence de la clé.map[string]bool, l'option avec struct{} est plus économique en mémoire.Canaux pour la signalisation :
done := make(chan struct{}) // La goroutine attend le signal de fin <-done
Quelle est la différence entre map[string]struct{} et map[string]bool lors de la mise en œuvre d'un ensemble ? Pourquoi map[string]struct{} est-il préférable et a-t-il des inconvénients ?
Réponse :
map[string]struct{} utilise 0 octet pour la valeur, c'est l'option la plus compacte — cela économise de la mémoire, surtout avec un grand nombre de données.map[string]bool nécessite 1 octet pour la valeur (internement, cela peut toujours occuper plus de mémoire à cause de l'alignement).map[string]struct{} : il n'est pas possible d'obtenir rapidement la liste de toutes les valeurs marquées true, au cas où une valeur logique serait nécessaire. Il faut tout de même parcourir les clés.Exemple :
set := make(map[string]struct{}) set["Alice"] = struct{}{} _, exists := set["Alice"] // true flags := make(map[string]bool) flags["Alice"] = true _, exists := flags["Alice"] // true
Histoire
Dans le projet de stockage d'identifiants uniques, nous avons utilisé map[string]bool, ce qui, avec l'augmentation des données, a conduit à une consommation de mémoire significative — des centaines de mégaoctets par rapport à l'option map[string]struct{}. Le passage à struct{} a réduit la consommation de mémoire de plus de la moitié.
Histoire
Un novice a signalé la fin d'une goroutine via
chan bool. Avec un grand nombre de goroutines, le passage de la valeur s'est révélé superflu : nulle part il n'était analysé sitrueoufalseétait arrivé. Le remplacement parchan struct{}a révélé une imprécision architecturale et a permis de simplifier le code.
Histoire
Dans la bibliothèque, ils ont créé un ensemble via map, où la valeur utilisée était string. Cela consommait trop de mémoire. Après une revue de code, ils ont changé pour map[typo]struct{}. L'erreur a été découverte après l'analyse du profil mémoire lors des tests de charge, lorsque l'application échouait à cause d'une OOM.