Array contre slice
Go propose deux façons de stocker une liste de valeurs. L'array a une taille fixée à la déclaration et qui ne bouge plus jamais :
var nombres [3]int // un array de 3 entiers, taille figée
nombres[0] = 10
En pratique, vous utiliserez le slice 99 % du temps. C'est la version dynamique : il grandit et rétrécit à volonté. On le reconnaît aux crochets vides [] devant le type :
scores := []int{10, 20, 30} // slice littéral
vide := []int{} // slice vide
autre := make([]int, 0) // même chose avec make
La différence clé : [3]int est un array (taille fixe), []int est un slice (taille dynamique). Quand vous hésitez, prenez le slice.
append, len et le slicing
Pour ajouter un élément, on utilise append. Il renvoie un nouveau slice qu'on réaffecte à la variable. len donne la taille :
scores := []int{10, 20, 30}
scores = append(scores, 40) // [10 20 30 40]
fmt.Println(len(scores)) // 4
Le slicing s[debut:fin] extrait une portion. La borne de début est incluse, celle de fin est exclue :
scores := []int{10, 20, 30, 40}
milieu := scores[1:3] // [20 30] : index 1 et 2, pas 3
Sortie attendue :
[10 20 30 40]
4
[20 30]
À vous d'essayer :
package main
import "fmt"
func main() {
scores := []int{10, 20, 30}
scores = append(scores, 40)
fmt.Println(scores)
fmt.Println(len(scores))
fmt.Println(scores[1:3])
}
Parcourir avec range
Pour parcourir un slice, la boucle for ... range vous donne à chaque tour l'index et la valeur :
fruits := []string{"pomme", "banane", "cerise"}
for i, v := range fruits {
fmt.Println(i, v)
}
Si l'index ne vous intéresse pas, remplacez-le par _ (le blank identifier). Go vous oblige à le faire, sinon il râle sur la variable inutilisée.
Sortie attendue :
0 pomme
1 banane
2 cerise
À vous d'essayer :
package main
import "fmt"
func main() {
fruits := []string{"pomme", "banane", "cerise"}
for i, v := range fruits {
fmt.Println(i, v)
}
}
Les maps : clé / valeur
Une map associe des clés à des valeurs, comme un dictionnaire en Python ou un objet en JavaScript. Le type s'écrit map[TypeCle]TypeValeur :
ages := map[string]int{
"Alice": 30,
"Bob": 25,
}
ages["Charlie"] = 42 // écrire
fmt.Println(ages["Alice"]) // lire : 30
Problème : que renvoie ages["Inconnu"] ? Pas une erreur, mais la valeur zéro du type (ici 0). Impossible alors de distinguer "la clé vaut 0" de "la clé n'existe pas". La solution est l'idiome comma-ok :
v, ok := ages["Inconnu"]
if ok {
fmt.Println("trouvé :", v)
} else {
fmt.Println("clé absente")
}
Le second retour ok est un booléen : true si la clé existe, false sinon. Pour supprimer une clé, on utilise delete, et on parcourt une map avec range :
delete(ages, "Bob") // supprime la clé "Bob"
for nom, age := range ages {
fmt.Println(nom, age)
}
Attention : accéder à une clé absente ne provoque jamais d'erreur en Go : la map renvoie silencieusement la valeur zéro du type (0 pour un int, "" pour une string, nil pour un pointeur). C'est exactement pour ça que l'idiome comma-ok v, ok := m[cle] existe : seul ok vous dit si la clé était vraiment là.
Sortie attendue :
30
clé absente
Alice 30
Charlie 42
À vous d'essayer :
package main
import "fmt"
func main() {
ages := map[string]int{"Alice": 30, "Bob": 25}
ages["Charlie"] = 42
fmt.Println(ages["Alice"])
if _, ok := ages["Inconnu"]; !ok {
fmt.Println("clé absente")
}
delete(ages, "Bob")
for nom, age := range ages {
fmt.Println(nom, age)
}
}
Array vs slice
Go offers two ways to store a list of values. An array has a size fixed at declaration that never changes again:
var numbers [3]int // an array of 3 ints, frozen size
numbers[0] = 10
In practice, you'll use the slice 99% of the time. It's the dynamic version: it grows and shrinks at will. You recognize it by the empty brackets [] before the type:
scores := []int{10, 20, 30} // slice literal
empty := []int{} // empty slice
other := make([]int, 0) // same thing with make
The key difference: [3]int is an array (fixed size), []int is a slice (dynamic size). When in doubt, use the slice.
append, len and slicing
To add an element, use append. It returns a new slice that you reassign to the variable. len gives the size:
scores := []int{10, 20, 30}
scores = append(scores, 40) // [10 20 30 40]
fmt.Println(len(scores)) // 4
Slicing s[start:end] extracts a portion. The start bound is included, the end bound is excluded:
scores := []int{10, 20, 30, 40}
middle := scores[1:3] // [20 30] — index 1 and 2, not 3
Expected output:
[10 20 30 40]
4
[20 30]
Looping with range
To loop over a slice, the for ... range loop gives you the index and the value on each iteration:
fruits := []string{"apple", "banana", "cherry"}
for i, v := range fruits {
fmt.Println(i, v)
}
If you don't need the index, replace it with _ (the blank identifier). Go forces you to do this, otherwise it complains about the unused variable.
Expected output:
0 apple
1 banana
2 cherry
Maps: key / value
A map associates keys with values, like a dictionary in Python or an object in JavaScript. The type is written map[KeyType]ValueType:
ages := map[string]int{
"Alice": 30,
"Bob": 25,
}
ages["Charlie"] = 42 // write
fmt.Println(ages["Alice"]) // read: 30
The catch: what does ages["Unknown"] return? Not an error, but the zero value of the type (here 0). So you can't tell "the key equals 0" from "the key doesn't exist". The solution is the comma-ok idiom:
v, ok := ages["Unknown"]
if ok {
fmt.Println("found:", v)
} else {
fmt.Println("missing key")
}
The second return value ok is a boolean: true if the key exists, false otherwise. To remove a key, use delete, and loop over a map with range:
delete(ages, "Bob") // removes the key "Bob"
for name, age := range ages {
fmt.Println(name, age)
}
Warning: accessing a missing key never raises an error in Go: the map silently returns the zero value of the type (0 for an int, "" for a string, nil for a pointer). This is exactly why the comma-ok idiom v, ok := m[key] exists: only ok tells you whether the key was really there.
Expected output:
30
missing key
Alice 30
Charlie 42
Copiez les exemples ci-dessus et testez-les dans le Go Playground :
Copiez ce prompt dans Claude ou ChatGPT :
Écris un programme Go qui compte le nombre d'occurrences de chaque mot dans une phrase, en utilisant une map[string]int. Explique l'idiome comma-ok dans le code.
Sans relire le code de l'IA : avec tes mots, pourquoi l'idiome v, ok := m[cle] existe-t-il, alors que m[cle] tout court fonctionne déjà ?
m[cle] sur une clé absente ne plante pas, il renvoie la valeur zéro du type (0, "", nil). Du coup une vraie valeur 0 est indistinguable d'une clé manquante. v, ok := m[cle] ajoute un second retour booléen : ok vaut true seulement si la clé existait. C'est ok, pas v, qui répond à la question « la clé est-elle là ? ».L'IA te propose ce code pour savoir si un utilisateur a un stock enregistré. Ton rôle de relecteur : l'accepter tel quel ou le rejeter, et dire pourquoi.
stock := map[string]int{"pommes": 0, "bananes": 12}
if stock["pommes"] != 0 {
fmt.Println("On a des pommes en stock")
} else {
fmt.Println("Plus de pommes... ou jamais enregistrées ?")
}
stock["pommes"] != 0 confond « 0 pomme en stock » avec « clé absente ». Ici "pommes" existe et vaut 0, donc le code dit « plus de pommes » alors que la donnée est bien enregistrée. Pire : si la clé n'existait pas, il dirait pareil. La correction est l'idiome comma-ok : v, ok := stock["pommes"], puis on teste ok pour l'existence et v pour la quantité. Ne jamais déduire l'existence d'une clé à partir de sa valeur.Sans remonter dans la leçon : qu'est-ce qui distingue [3]int de []int, et que vaut ok dans v, ok := m[cle] quand la clé est absente ?
[3]int est un array : taille fixe, figée à la déclaration. []int (crochets vides) est un slice : taille dynamique, on l'agrandit avec append. En pratique on prend le slice 99 % du temps. Pour la map, quand la clé est absente ok vaut false et v reçoit la valeur zéro du type ; ok est donc le seul moyen fiable de savoir si la clé existait.Vos données sont bien rangées dans des slices et des maps. On va maintenant les manipuler avec des fonctions qui renvoient plusieurs valeurs, dont la fameuse paire (résultat, error) : vous découvrez pourquoi Go ignore try/catch et gère ses erreurs avec if err != nil, plus le mot-clé defer.
Leçon 5 : Fonctions et erreurs →