ProgrammationDéveloppeur Backend

Qu'est-ce qu'une structure vide struct{} en Go et quand l'utiliser ? Quelles sont les possibilités et les subtilités de son utilisation, en particulier dans le contexte de l'optimisation de la mémoire et de la mise en œuvre d'un ensemble (set) ou de canaux pour la signalisation ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse

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é.
  • Contrairement à 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
  • À travers ce canal, un simple événement est envoyé, et non des données.

Question piège

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).
  • La logique est identique dans les deux versions — la valeur n'a pas d'importance, seule la présence de la clé compte.
  • Inconvénient de 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

Exemples d'erreurs réelles dues à des méconnaissances des subtilités du sujet


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é si true ou false était arrivé. Le remplacement par chan 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.