Vol. 6 — № 01
The Go Loop · KiosqueNewsstand
Blog  
Un atelier Go · Édition d'ApprentissageA Go Workshop · Learning Edition

Tout est copié Everything is copied

En Go, passer une valeur, c'est la copier — struct comprise, champ par champ. Parfois c'est un service (une copie ne peut pas être mutée ailleurs), parfois c'est un coût (une grosse struct recopiée à chaque appel). Savoir lequel, c'est tout l'art. In Go, passing a value copies it — structs included, field by field. Sometimes that's a gift (a copy can't be mutated elsewhere), sometimes a cost (a big struct re-copied on every call). Knowing which is the whole craft.

AudienceAudience
Dev qui modifie une struct dans une fonction et s'étonne que l'original n'ait pas bougé Dev who modifies a struct in a function and is surprised the original didn't move
Format
Self-paced
ChapitresChapters
5
Date
Sep 2027 Sep 2027
≈ 16 min ●●○○ ValeurCopie

Chapitre 1 en accès libre — la suite (ch. 2 à 5) est réservée. Chapter 1 free to read — the rest (ch. 2–5) is members-only.

01CadrageFraming3 min

En Go, dès que tu passes une valeur, tu la copies. C'est la règle qui gouverne tout le reste.In Go, the moment you pass a value, you copy it. That's the rule governing everything else.

Le volume 5 nous a montré des structures qui partagent une mémoire sous-jacente — une slice et son tableau, une map et sa table. On pourrait en conclure que partager est la norme en Go. C'est l'exact contraire. Le comportement par défaut du langage, celui dont tout le reste découle, c'est la copie. Assigner une variable à une autre, passer un argument à une fonction, ranger une valeur dans un tableau ou la renvoyer d'une fonction : à chacun de ces gestes, Go duplique la valeur, champ par champ. Pas de référence implicite, pas de partage caché — une copie franche, dont les modifications n'ont aucun effet sur l'original. C'est vrai des entiers, c'est vrai des structs, c'est vrai des tableaux de taille fixe. Cette sémantique de valeur a deux visages, et tout l'art consiste à savoir lequel tu regardes. Côté pile, c'est un service : une copie ne peut pas être mutée à distance, donc une fonction qui reçoit ta struct ne peut pas, par mégarde, corrompre la tienne. Côté face, c'est un coût : une grosse struct recopiée à chaque appel, c'est de la mémoire et du temps dépensés à dupliquer. Comprendre la sémantique de valeur, c'est savoir reconnaître, à chaque passage, lequel des deux tu paies — et choisir un pointeur quand le coût l'emporte, ou quand tu veux justement muter l'original.Volume 5 showed us structures that share an underlying memory — a slice and its array, a map and its table. You might conclude that sharing is the norm in Go. It's the exact opposite. The language's default behavior, the one everything else flows from, is the copy. Assigning one variable to another, passing an argument to a function, storing a value in an array or returning it from a function: at each of these moves, Go duplicates the value, field by field. No implicit reference, no hidden sharing — a clean copy, whose modifications have no effect on the original. It's true of integers, true of structs, true of fixed-size arrays. This value semantics has two faces, and the whole craft is knowing which one you're looking at. Heads, it's a gift: a copy can't be mutated at a distance, so a function receiving your struct can't accidentally corrupt yours. Tails, it's a cost: a big struct re-copied on every call is memory and time spent duplicating. Understanding value semantics is knowing how to recognize, at each pass, which of the two you're paying — and choosing a pointer when the cost wins, or when you actually want to mutate the original.

Assignation : la copie est indépendanteAssignment: the copy is independent
type Point struct{ X, Y int }

a := Point{1, 2}
b := a                  // COPIE : b est un Point indépendant, champ par champ
b.X = 99
fmt.Println(a)          // {1 2}   ← a intact, aucun lien avec b
fmt.Println(b)          // {99 2}
Appel de fonction : l'argument est copié, l'original protégéFunction call: the argument is copied, the original protected
func reset(p Point) {   // p est une COPIE de l'argument passé
    p.X = 0             // … on modifie la copie locale, pas l'original
}

a := Point{1, 2}
reset(a)                // a est copié dans p au moment de l'appel
fmt.Println(a)          // {1 2}   ← reset n'a jamais touché le vrai a
La copie a deux visagesThe copy has two faces
un service
une copie ne peut pas être mutée ailleurs — ta valeur est protégée
|
un coût
une grosse struct recopiée à chaque passage — mémoire et temps

La même opération — copier — est tantôt une protection, tantôt une dépense. Rien dans le code ne dit lequel ; c'est la taille de la valeur et ton intention qui tranchent. Tout le volume apprend à lire ce choix.The same operation — copying — is sometimes a protection, sometimes an expense. Nothing in the code says which; it's the value's size and your intent that decide. The whole volume teaches you to read that choice.

Le réflexe du numéroThe issue's reflex

« Je passe une valeur ? alors je passe une copie — sauf si je passe un pointeur. » C'est la grille de lecture de tout le langage. Une fonction ne peut muter ce que tu lui donnes que si tu lui donnes l'adresse, pas la valeur. Le volume 5 était l'exception qui partage ; celui-ci est la règle qui isole. Et il révèle au passage pourquoi la slice et la map se comportaient si différemment : ce qu'on en copie, c'est leur en-tête, pas leur contenu."Am I passing a value? then I'm passing a copy — unless I pass a pointer." It's the reading grid for the entire language. A function can only mutate what you give it if you give it the address, not the value. Volume 5 was the exception that shares; this one is the rule that isolates. And it reveals along the way why the slice and the map behaved so differently: what you copy of them is their header, not their content.

« Copié », ce n'est pas « cloné en profondeur »'Copied' isn't 'deep-cloned'

Un point de vocabulaire, qu'on déplie au chapitre 3 : copier une valeur en Go, c'est dupliquer ses champs tels quels — pas suivre récursivement ce vers quoi ils pointent. Copier une struct qui contient un int et un bool donne deux champs neufs, totalement indépendants. Mais copier une struct qui contient une slice duplique l'en-tête de la slice — ses trois mots — sans dupliquer le tableau sous-jacent. Les deux copies pointent alors vers le même tableau. C'est une copie « de surface » (shallow), et c'est le pont exact entre ce volume et le précédent : la sémantique de valeur copie fidèlement, mais ce qu'elle copie d'une slice, c'est précisément la vue partagée qu'on a étudiée tout le volume 5.A point of vocabulary, unfolded in chapter 3: copying a value in Go duplicates its fields as they are — not recursively following what they point to. Copying a struct holding an int and a bool gives two fresh, fully independent fields. But copying a struct holding a slice duplicates the slice's header — its three words — without duplicating the underlying array. Both copies then point at the same array. It's a 'shallow' copy, and it's the exact bridge between this volume and the last: value semantics copies faithfully, but what it copies of a slice is precisely the shared view we studied all through volume 5.

🔒

La suite est réservée The rest is members-only

Le premier numéro est libre. Débloque tout The Go Loop — tous les volumes, à vie — pour 5 €, paiement unique. The first issue is free. Unlock all of The Go Loop — every volume, forever — for €5, one-time.

Retour au kiosqueBack to newsstand