Delete key in map : comment ça fonctionne sous le capot en Go
\n\nVous êtes-vous déjà demandé ce qui se passe réellement lorsque vous écrivez delete(myMap, "key") en Go ? La clé disparaît-elle simplement de la mémoire ? Ou reste-t-il un "trou" ? Et que se passe-t-il si vous supprimez une clé d'une map nil ? Si vous vous êtes posé ces questions, vous n'êtes pas seul. Le sujet delete key in map a rassemblé des milliers de vues sur Stack Overflow, et aujourd'hui, nous allons jeter un coup d'œil sous le capot de cette action en apparence simple.
Dans cet article SEO, nous allons analyser comment est structurée la table de hachage en Go (la structure hmap), comment fonctionne la suppression d'une clé, où va la mémoire et pourquoi il ne faut pas avoir peur de delete dans les boucles. C'est parti !
Brève introduction : comment est structurée une map en Go
\n\nAvant de parler de suppression, rappelons comment la map golang stocke les données. En interne, il s'agit d'une table de hachage, la structure hmap. Elle est composée d'un tableau de "seaux" (buckets), chacun pouvant stocker jusqu'à 8 paires clé-valeur. Lorsque vous ajoutez une clé, Go calcule le hachage, trouve le seau et place la paire à l'intérieur. Si le seau est plein, une chaîne de débordement (overflow bucket) est créée.
C'est une implémentation classique, mais avec quelques astuces dont nous parlerons plus bas.
\n\nStructure de hmap (simplifiée)
\n\ntype hmap struct {\n count int // nombre d'éléments\n flags uint8\n B uint8 // logarithme du nombre de seaux\n buckets unsafe.Pointer // pointeur vers le tableau de seaux\n oldbuckets unsafe.Pointer // lors de la croissance de la map\n nevacuate uintptr\n // ...\n}\n\nPoint clé : buckets est un tableau contigu. La suppression ne réduit pas ce tableau, elle marque seulement la cellule comme "vide".
Delete key in map : comment ça fonctionne au niveau du code
\n\nL'appel delete(m, k) en Go est une fonction intégrée qui est compilée en un appel au runtime. En interne, voici ce qui se passe approximativement :
- \n
- Calcul du hachage de la clé — Go utilise une fonction de hachage spécifique au type de la clé. \n
- Recherche du seau — les bits de poids faible du hachage déterminent le numéro du seau. \n
- Recherche linéaire à l'intérieur du seau (et des chaînes de débordement) — trouve la cellule avec la clé souhaitée. \n
- Nettoyage de la mémoire — Go remet à zéro la mémoire de la clé et de la valeur, afin que le ramasse-miettes puisse les collecter. \n
- Marquage de la cellule comme "vide" — un indicateur spécial
emptyRestouemptyOne. \n - Décrémentation du compteur —
m.count--. \n
Tout cela se fait en O(1) en moyenne, mais en tenant compte des collisions, cela peut être O(n) dans le pire des cas.
\n\nExemple de code : delete en action
\n\npackage main\n\nimport "fmt"\n\nfunc main() {\n m := map[string]int{\n "apple": 5,\n "banana": 3,\n "cherry": 7,\n }\n\n fmt.Println("Avant la suppression :", m)\n delete(m, "banana")\n fmt.Println("Après la suppression :", m)\n\n // Essayons de supprimer une clé inexistante\n delete(m, "grape") // rien ne se passe, pas d'erreur\n fmt.Println("Après la suppression d'une clé inexistante :", m)\n}\n\nNotez bien : delete key in map pour une clé inexistante est une opération sûre. Elle ne fait simplement rien. C'est une idée fausse courante chez les débutants.
\n\nQue se passe-t-il avec la mémoire ? Mythes et réalité
\n\nDe nombreux développeurs craignent qu'après un delete, il reste des "trous" dans la map, entraînant des fuites mémoire. Clarifions cela.
Mémoire pour les clés et les valeurs
\n\nLorsque vous supprimez une clé, Go remet à zéro la mémoire de cet élément. Si la clé ou la valeur étaient des pointeurs ou contenaient des pointeurs (chaînes, slices, maps), le ramasse-miettes pourra les collecter. La cellule elle-même dans le seau reste, mais est marquée comme vide.
\n\nCela signifie que la map ne réduit pas sa taille en