Les tableaux et les slices en Go

Comprenez les tableaux et les slices en Go : littéraux, len et cap, append, découpage, make, parcours, et le partage du tableau sous-jacent.

Prérequis

Objectifs pédagogiques

  • Distinguer tableaux et slices et savoir quand utiliser chacun
  • Agrandir une slice avec append et lire len et cap
  • Comprendre que les slices partagent un tableau sous-jacent

Un tableau a une longueur fixe qui fait partie de son type. Une slice est une vue souple et extensible sur un tableau. Au quotidien en Go, on utilise presque toujours des slices, mais comprendre le tableau en dessous est ce qui fait « déclic ».

Les tableaux : une taille fixe

La longueur d’un tableau est fixée à la déclaration et ne peut pas changer. La taille fait partie du type : [3]string et [4]string sont donc deux types différents.

var days [3]string
days[0] = "Lun"
days[1] = "Mar"
days[2] = "Mer"

Comme la longueur est figée, les tableaux sont rigides. C’est pour cela que les slices existent.

Les slices : une vue souple

Un littéral de slice ressemble à un littéral de tableau, sans la taille. Une slice n’a pas de longueur fixe et peut grandir.

primes := []int{2, 3, 5, 7}

len et cap

len renvoie le nombre d’éléments actuellement contenus. cap renvoie combien elle peut en contenir avant de devoir agrandir son stockage sous-jacent.

s := []int{2, 3, 5, 7}
fmt.Println(len(s), cap(s)) // 4 4

Agrandir une slice avec append

append renvoie une nouvelle slice contenant les éléments ajoutés. Réaffectez toujours le résultat, en général à la même variable.

s := []int{1, 2}
s = append(s, 3, 4)
// s vaut maintenant [1 2 3 4]

Découper avec a[low:high]

a[low:high] produit une slice de l’indice low jusqu’à high exclu. Chaque borne peut être omise pour signifier « le début » ou « la fin ».

lettres := []string{"a", "b", "c", "d", "e"}
fmt.Println(lettres[1:3]) // [b c]
fmt.Println(lettres[:2])  // [a b]
fmt.Println(lettres[3:])  // [d e]

Parcourir avec range

for range parcourt une slice en fournissant l’indice et une copie de chaque élément.

for i, v := range primes {
	fmt.Println(i, v)
}

Créer des slices avec make

make construit une slice avec une longueur donnée et, éventuellement, une capacité. C’est l’outil adapté quand vous savez à peu près combien d’éléments vous ajouterez.

scores := make([]int, 0, 4) // len 0, cap 4
scores = append(scores, 10) // pas encore de réallocation

Les slices partagent un tableau sous-jacent

C’est le piège classique. Une slice pointe vers un tableau, et les sous-slices partagent ce même tableau. Écrire à travers une vue modifie l’autre.

base := []int{1, 2, 3, 4}
view := base[1:3] // [2 3]
view[0] = 99
fmt.Println(base) // [1 99 3 4]

Un exemple complet

Ce programme construit une slice, y ajoute des éléments, en extrait une sous-slice et additionne des valeurs collectées avec make. Il compile et s’exécute tel quel.

package main

import "fmt"

func main() {
	// Un littéral de slice.
	primes := []int{2, 3, 5, 7}
	fmt.Println("primes :", primes, "len :", len(primes), "cap :", cap(primes))

	// On l’agrandit avec append.
	primes = append(primes, 11, 13)
	fmt.Println("après append :", primes)

	// Une sous-slice partage le même tableau sous-jacent.
	troisPremiers := primes[:3]
	fmt.Println("trois premiers :", troisPremiers)

	// make crée une slice avec une longueur et une capacité.
	scores := make([]int, 0, 4)
	for i := 1; i <= 4; i++ {
		scores = append(scores, i*i)
	}

	// On parcourt avec range.
	sum := 0
	for _, s := range scores {
		sum += s
	}
	fmt.Println("scores :", scores, "somme :", sum)
}

Son exécution affiche :

primes : [2 3 5 7] len : 4 cap : 4
après append : [2 3 5 7 11 13]
trois premiers : [2 3 5]
scores : [1 4 9 16] somme : 30

Erreurs fréquentes

  • Ignorer le résultat d’append. append(s, x) seul perd la nouvelle slice ; vous devez écrire s = append(s, x).
  • Oublier le tableau sous-jacent partagé. Deux slices issues du même tableau voient les écritures l’une de l’autre. Copiez si vous avez besoin d’indépendance.
  • Confondre len et cap. len est ce que vous pouvez lire aujourd’hui ; cap est la limite du stockage avant une réallocation.

À vous de jouer

Avec numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, construisez une nouvelle slice ne contenant que les nombres pairs et affichez-la.

Afficher la correction
package main

import "fmt"

func main() {
	numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

	evens := make([]int, 0, len(numbers))
	for _, n := range numbers {
		if n%2 == 0 {
			evens = append(evens, n)
		}
	}

	fmt.Println(evens)
}

Partir d’une slice vide de capacité len(numbers) évite les réallocations, et la boucle range ajoute chaque valeur paire, affichant [2 4 6 8 10].

Résumé

  • Les tableaux ont une longueur fixe ; les slices sont des vues souples, que l’on utilise le plus souvent.
  • append renvoie une nouvelle slice, len/cap la décrivent, et make la pré-dimensionne.
  • Les slices partagent un tableau sous-jacent : utilisez copy pour en obtenir une indépendante.

Ensuite, découvrez l’autre collection centrale de Go, les maps clé-valeur, et revenez sur l’itération avec les boucles.

Votre progression est enregistrée uniquement dans ce navigateur. Aucun compte n’est requis.

Recherche

La recherche s’exécute entièrement dans votre navigateur.