Closure ! 😓
Les closures sont un concept puissant en programmation qui permet de capturer et de se souvenir des variables de leur environnement. Cela permet de créer des fonctions plus dynamiques et flexibles.
Qu'est-ce qu'un closure ?
Une closure est une fonction qui "se souvient" de l’environnement dans lequel elle a été créée.
Autrement dit, une closure peut capturer et conserver des variables externes même après que la fonction extérieure ait terminé son exécution.
Exemple simple
Imagine que tu ouvres une boîte et que tu mets un chiffre à l’intérieur. Ensuite, chaque fois que tu ouvres cette boîte, tu peux voir et modifier ce chiffre.
Une closure, c’est un peu comme une boîte qui se souvient de son contenu ! 📦
Créer une closure
Création d'un closure pas à pas
Étape 1 : Créer la fonction
func counter() {
}
Étape 2 : Ajouter le type de retour
On va retourner une fonction anonyme, que l'on appelle closure dans ce contexte.
func counter() func() int {
}
Étape 3 : Ajouter une variable capturée
func counter() func() int {
count := 0 // Cette variable sera capturée par la closure
}
La valeur de la variable count
sera retenue par la closure.
Étape 4 : Retourner la fonction anonyme (closure)
func counter() func() int {
count := 0
return func() int {
count++
return count
}
}
Closure terminée
Et voilà, c’est fini ! La closure est prête ! Ne faites pas attention au 5
, c’est juste un chiffre choisi au hasard pour l’exemple.
Avec un paramètre
Voici un exemple où nous définissons une fonction multiplier qui retourne une closure :
package main
import "fmt"
// Fonction qui retourne une closure
func multiplier(factor int) func(int) int {
return func(number int) int {
return number * factor
}
}
func main() {
// Création d'une closure qui multiplie par 2
double := multiplier(2)
// Création d'une closure qui multiplie par 3
triple := multiplier(3)
fmt.Println("Double de 5 :", double(5)) // Affiche : Double de 5 : 10
fmt.Println("Triple de 5 :", triple(5)) // Affiche : Triple de 5 : 15
}
Dans cet exemple, La fonction multiplier
prend un nombre factor
et retourne une nouvelle fonction (une closure).
Cette closure prend un autre nombre number
et le multiplie par factor
.
Quand on crée double := multiplier(2)
, on fabrique une closure qui se souvient que factor vaut 2
.
Quand on appelle double(5)
, la closure se souvient de factor et retourne 5 * 2 = 10
.
Les closures permettent donc de créer des fonctions "prêtes à l’emploi".

Avec une variable externe 💪
Lorsqu’une closure est créée, elle capture les variables de son environnement externe. Ces variables restent accessibles même si la fonction extérieure a terminé son exécution.
Prenons un autre exemple pour bien comprendre :
package main
import "fmt"
// Fonction qui retourne une closure qui incrémente un compteur
func counter() func() int {
count := 0
return func() int {
count++
return count
}
}
func main() {
c := counter()
fmt.Println(c()) // Affiche : 1
fmt.Println(c()) // Affiche : 2
fmt.Println(c()) // Affiche : 3
}
Dans le code ci-dessus, la fonction counter
initialise une variable count
à 0
et retourne une closure qui incrémente et renvoie cette variable chaque fois qu’elle est appelée.
Chaque appel à c()
incrémente count
de 1
, ce qui prouve que la closure retient la valeur de count
entre les appels, même après que la fonction counter
ait terminé.

🦸🏻♂️ Encore mieux comprendre en comparant une fonction normal et une closure !
"Transformer" la closure en fonction normal
Pour encore mieux comprendre les closures, nous allons adapter la dernière closure pour la transformer en fonction :
package main
import "fmt"
// -- Closure --
func counterClosure() func() int {
count := 0
return func() int {
count++
return count
}
}
// -- Fonction --
func counterFunction() int {
count := 0
count++
return count
}
func main() {
fmt.Println(" -- Closure --")
c := counterClosure()
fmt.Println(c()) // Affiche : 1
fmt.Println(c()) // Affiche : 2
fmt.Println(c()) // Affiche : 3
fmt.Println(" -- Fonction --")
fmt.Println(counterFunction()) // Affiche : 1
fmt.Println(counterFunction()) // Affiche : 1
fmt.Println(counterFunction()) // Affiche : 1
}
Résultat !
on exécute le programme :
go run main/go
Résultat :
-- Closure --
1
2
3
-- Fonction --
1
1
1
Comparer
Vous avez peut-être remarqué une différence avec la variable count
.
Dans une closure, la valeur de count
est mémorisée entre chaque appel de la fonction.
En revanche, dans une fonction normale, count
est réinitialisé à chaque appel.
﹅ | Closure | Fonction |
---|---|---|
Variable persistante ? | ✅ Oui | ❌ Non |
Réinitialisation ? | ❌ Non | ✅ Oui à chaque appel |
Conclusion
-
Une closure mémorise la variable et la garde entre les appels.
-
Une fonction classique réinitialise la variable à chaque appel.