Les maps en Go

Apprenez à créer et utiliser les maps en Go : littéraux et make, l’idiome virgule-ok, delete, len et le parcours des clés, avec un exemple exécutable.

Prérequis

Objectifs pédagogiques

  • Créer des maps avec un littéral et avec make, puis lire et écrire des valeurs
  • Utiliser l’idiome virgule-ok pour distinguer une clé absente d’une valeur zéro
  • Supprimer des clés, compter les entrées et parcourir une map sans risque

Une map en Go est une collection non ordonnée de paires clé/valeur, notée map[K]V. Elle offre une recherche rapide par clé — la même idée qu’un dictionnaire en Python ou qu’un objet en JavaScript, mais typée statiquement.

Créer une map

Vous pouvez construire une map à partir d’un littéral ou la créer vide avec la fonction intégrée make. Dans les deux cas, la map est prête à l’emploi ; les clés doivent être d’un type comparable comme une chaîne, un entier ou un booléen.

// Un littéral de map avec deux entrées.
ages := map[string]int{
	"Ada":  36,
	"Alan": 41,
}

// Une map vide prête à recevoir des écritures, créée avec make.
scores := make(map[string]int)

Lire et écrire des valeurs

Vous écrivez avec m[clé] = valeur et vous lisez avec m[clé]. Une clé absente ne provoque pas d’erreur : sa lecture renvoie la valeur zéro du type des valeurs.

scores["Ada"] = 100      // écriture
top := scores["Ada"]     // lecture : 100
absente := scores["Bob"] // clé absente : valeur zéro, 0

L’idiome virgule-ok

Comme une clé absente renvoie une valeur zéro, scores["Bob"] == 0 ne permet pas de savoir si Bob a marqué zéro ou s’il est simplement absent. La forme à deux valeurs de la lecture règle le problème : la seconde valeur est un booléen true uniquement lorsque la clé existe.

if score, ok := scores["Bob"]; ok {
	fmt.Println("trouvé :", score)
} else {
	fmt.Println("Bob n’a pas encore de score")
}

Supprimer des clés et compter avec len

delete retire une clé (et ne fait rien si la clé est absente). len renvoie le nombre d’entrées.

delete(scores, "Ada") // retire une clé
total := len(scores)  // nombre d’entrées restantes

Parcourir une map

Une boucle for ... range visite chaque paire clé/valeur. L’ordre est volontairement aléatoire, imposé par le runtime : ne vous y fiez jamais. Si vous avez besoin d’un ordre stable, collectez les clés dans une slice et triez-les.

for nom, score := range scores {
	fmt.Printf("%s -> %d\n", nom, score)
}

Un exemple complet

Le programme ci-dessous compte le nombre d’occurrences de chaque mot d’une phrase. Il trie les clés avant l’affichage pour un résultat déterministe. Il compile et s’exécute tel quel.

package main

import (
	"fmt"
	"sort"
	"strings"
)

func main() {
	text := "the quick brown fox the lazy dog the end the fox"
	counts := make(map[string]int)

	for _, word := range strings.Fields(text) {
		counts[word]++
	}

	// On collecte les clés puis on les trie pour un affichage stable,
	// car le parcours d’une map visite les clés dans un ordre aléatoire.
	words := make([]string, 0, len(counts))
	for word := range counts {
		words = append(words, word)
	}
	sort.Strings(words)

	for _, word := range words {
		fmt.Printf("%s: %d\n", word, counts[word])
	}
}

Son exécution affiche :

brown: 1
dog: 1
end: 1
fox: 2
lazy: 1
quick: 1
the: 4

Les maps sont des types référence

Une valeur de type map est un petit en-tête qui pointe vers les données sous-jacentes. Lorsque vous passez une map à une fonction, les deux côtés partagent le même stockage : les écritures faites dans la fonction sont visibles par l’appelant. C’est pratique, mais cela entraîne deux conséquences à garder en tête.

Erreurs fréquentes

  • Écrire dans une map nil. Déclarer var m map[string]int donne une map nil. Vous devez la créer avec make avant la première écriture.
  • Se fier à l’ordre du parcours. L’ordre d’itération change à chaque exécution, par conception. Triez les clés lorsque vous voulez un résultat reproductible.
  • Confondre absent et zéro. Utilisez la forme virgule-ok plutôt que de comparer la valeur à sa valeur zéro.
  • Prendre l’adresse d’une entrée. &m[clé] est interdit, car le runtime peut déplacer les entrées. Stockez une valeur, modifiez-la, puis réécrivez-la.

À vous de jouer

À partir d’une slice de chaînes de votes, construisez une map de comptes, puis utilisez l’idiome virgule-ok pour afficher le compte de "go", en affichant go: 0 s’il n’est jamais apparu.

Afficher la correction
package main

import "fmt"

func main() {
	votes := []string{"go", "rust", "go", "python", "go"}

	counts := make(map[string]int)
	for _, v := range votes {
		counts[v]++
	}

	if n, ok := counts["go"]; ok {
		fmt.Printf("go: %d\n", n)
	} else {
		fmt.Println("go: 0")
	}
}

Chaque tour de boucle incrémente le compteur du vote courant. La lecture virgule-ok distingue ensuite un vrai compte d’une clé absente. Ici, le programme affiche go: 3.

Résumé

  • Créez des maps avec un littéral ou make ; les clés doivent être comparables.
  • Une clé absente se lit comme la valeur zéro ; utilisez la forme virgule-ok pour en avoir le cœur net.
  • delete retire une clé, len compte les entrées, et l’ordre de range est aléatoire.
  • Les maps sont des types référence et ne sont pas sûres en écriture concurrente.

Ensuite, apprenez à modéliser des données plus riches avec les structs et les méthodes en Go. Pour revoir d’abord les collections ordonnées, relisez les tableaux et slices.

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.