Les structures map et slice en Go ont des particularités importantes en matière de copie et de sémantique de travail avec la mémoire, qui entraînent souvent un comportement inattendu chez les développeurs inexpérimentés.
Bien que Go soit considéré comme un langage rigoureux avec une typage statique et l'absence de pointeurs par défaut, map et slice ont un modèle interne spécial : les deux types sont des structures de référence. Cela impose des restrictions et crée de nombreux enjeux lors de la copie et du passage de ces objets.
La copie de map et slice ne conduit pas à une copie profonde du contenu, mais crée une nouvelle référence au même objet, ce qui entraîne des effets secondaires inattendus lors de la modification des données, d'un retour incorrect de valeurs depuis des fonctions et de modifications. De plus, le retour d'une map ou d'un slice comme résultat d'une fonction peut provoquer des allocations supplémentaires ou des fuites.
b := a[:]). Pour une copie complète des éléments, il faut utiliser la fonction intégrée copy().Exemple de copie correcte :
// Copie d'un slice a := []int{1, 2, 3} b := make([]int, len(a)) copy(b, a) // b est maintenant indépendant de a // Copie d'une map src := map[string]int{"x": 1} dst := make(map[string]int) for k, v := range src { dst[k] = v }
Caractéristiques clés :
slice et map sont des types de référence, copiés par descripteur, et non par contenuQue se passe-t-il si on assigne simplement une map/slice à une autre, puis qu'on modifie l'une d'elles ?
Les deux map et slice pointeront vers les mêmes données en mémoire : la modification affectera les deux objets.
Pourquoi dit-on souvent que retourner un slice ou une map depuis une fonction est "efficace en mémoire" ?
Parce qu'un clone du descripteur est retourné, et non de l'ensemble du contenu, les données dans le tas vivent tant qu'il y a des références sur elles.
Peut-on faire une "copie profonde" d'une map avec la fonction copy() ?
Non, copy() ne fonctionne qu'avec des slices et des tableaux, pour les maps, il faut toujours une boucle.
Un développeur copie un slice ou une map par assignation et modifie la copie pour se protéger contre les effets secondaires :
Avantages :
Inconvénients :
Avant de modifier les données nécessaires, la fonction copy() est utilisée pour les slices et une boucle pour les maps :
Avantages :
Inconvénients :