Aller au contenu
Développement medium

Slices, maps et tableaux en Go

9 min de lecture

Go

Les collections sont le pain quotidien de tout programme Go : listes de résultats, tables de correspondance, ensembles de valeurs. Ce guide vous apprend à manipuler les trois structures de base, les tableaux, les slices et les maps, et surtout à éviter le piège qui surprend tous les débutants : en Go, un slice partage sa mémoire, et modifier une vue peut modifier l'original. Public visé : vous connaissez déjà les variables et fonctions Go. Tous les exemples sont testés sur Go 1.26.

  • Distinguer un tableau à taille fixe d'un slice dynamique.
  • Faire croître un slice avec append et comprendre len/cap.
  • Éviter le piège du partage de mémoire grâce à copy.
  • Associer des clés à des valeurs avec une map.

Go propose deux structures pour une suite de valeurs. Le tableau (array) a une taille fixe, connue à la compilation. Le slice est une vue dynamique qui peut grandir : c'est celui qu'on utilise 95% du temps.

var tab [3]int = [3]int{1, 2, 3} // tableau : 3 cases, ni plus ni moins
sli := []int{1, 2, 3} // slice : pas de taille entre les crochets
sli = append(sli, 4) // on ajoute un élément
fmt.Println(tab, sli) // [1 2 3] [1 2 3 4]

La différence tient dans les crochets : [3]int fixe la taille, []int la laisse libre. Un tableau sert quand la taille est immuable et connue (une matrice, une couleur RVBA) ; partout ailleurs, on prend un slice.

Un slice a deux mesures : sa longueur (len, le nombre d'éléments) et sa capacité (cap, la place réservée en mémoire avant de devoir réallouer). La fonction make permet de pré-réserver cette capacité.

s := make([]int, 0, 2) // longueur 0, capacité 2
fmt.Printf("len=%d cap=%d\n", len(s), cap(s))
for i := 1; i <= 3; i++ {
s = append(s, i)
fmt.Printf("après append(%d): len=%d cap=%d\n", i, len(s), cap(s))
}

Sortie :

len=0 cap=2
après append(1): len=1 cap=2
après append(2): len=2 cap=2
après append(3): len=3 cap=4

Tant que la capacité suffit, append remplit les cases réservées. Au troisième ajout, la capacité de 2 est dépassée : Go réalloue un nouveau tableau plus grand (ici la capacité double à 4) et recopie les éléments. Pré-réserver avec make([]int, 0, N) quand on connaît la taille finale évite ces réallocations et accélère le code.

Voici l'erreur qui piège tout le monde. Un slice n'est pas les données : c'est une fenêtre sur un tableau en mémoire. Découper un slice avec base[1:3] crée une autre fenêtre sur le même tableau. Modifier l'une modifie l'autre.

base := []int{10, 20, 30, 40}
vue := base[1:3] // vue partage la mémoire de base
vue[0] = 99
fmt.Println(base) // [10 99 30 40] : base a changé !

On voulait ne toucher que vue, mais base est modifiée. Pour obtenir une copie indépendante, on alloue un nouveau slice et on utilise copy :

base2 := []int{10, 20, 30, 40}
indep := make([]int, 2)
copy(indep, base2[1:3])
indep[0] = 99
fmt.Println(base2, indep) // [10 20 30 40] [99 30] : base2 intacte

Retenez la règle : un sous-slice partage la mémoire de son parent. Dès que vous devez modifier une portion sans toucher l'original, passez par copy.

La map est la structure clé-valeur de Go, idéale pour indexer des données par un identifiant. On la crée avec un littéral ou make, et on accède aux valeurs par leur clé.

stock := map[string]int{"pommes": 5, "poires": 3}
stock["bananes"] = 7 // ajout ou mise à jour
if n, ok := stock["pommes"]; ok { // le second retour ok dit si la clé existe
fmt.Println("pommes en stock:", n)
}
delete(stock, "poires") // suppression

Le motif valeur, ok := map[clé] est essentiel : ok vaut false si la clé est absente, ce qui évite de confondre « clé absente » et « valeur zéro ». Un accès à une clé inexistante ne plante pas, il renvoie la valeur zéro du type (0 pour un int).

L'itération sur une map se fait avec range, mais l'ordre n'est pas garanti et change à chaque exécution. Pour un affichage stable, on trie les clés :

cles := make([]string, 0, len(stock))
for k := range stock {
cles = append(cles, k)
}
sort.Strings(cles) // ordre déterministe
for _, k := range cles {
fmt.Printf("%s: %d\n", k, stock[k])
}

Cet exercice combine slice et map. Essayez de le résoudre avant d'ouvrir la solution.

Écrivez un programme qui compte combien de fois chaque mot apparaît dans une phrase.

  • Partez d'un slice de mots : []string{"go", "est", "simple", "go", "est", "rapide", "go"}.
  • Construisez une map map[string]int qui associe chaque mot à son nombre d'occurrences.
  • Affichez combien de fois le mot "go" apparaît.

Indice : sur une map, compte[mot]++ fonctionne même si la clé n'existe pas encore (elle démarre à la valeur zéro 0).

  • Le tableau ([3]int) a une taille fixe ; le slice ([]int) est dynamique et sert dans la quasi-totalité des cas.
  • Un slice a une longueur (len) et une capacité (cap) ; append réalloue quand la capacité est dépassée.
  • Piège majeur : un sous-slice base[1:3] partage la mémoire du parent ; utilisez copy pour une copie indépendante.
  • La map associe des clés à des valeurs ; le motif v, ok := m[k] teste la présence d'une clé.
  • L'ordre d'itération d'une map n'est pas garanti : triez les clés pour un affichage stable.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn