Passer au contenu principal
eLearner.app
Module 3 · Leçon 5 sur 515/50 dans le cours~12 min
Leçons du module (5/5)

defer : nettoyage garanti

defer reporte l'exécution d'un appel jusqu'à la fonction englobante renvoie. Il s'exécute même si la fonction se termine par panique. Plusieurs defer dans la même fonction, exécutez dans l'ordre LIFO (Dernier entré, Premier sorti).

C'est le mécanisme idiomatique du nettoyage des ressources : fermer les fichiers, déverrouiller les mutex, libérer les connexions, restaurer l'état.

Syntaxe et cas d'utilisation canonique

Go
f, err := os.Open(path)
if err != nil {
    return err
}
defer f.Close()   // chiamata SEMPRE all'uscita della funzione

// ... usa f liberamente ...
return nil

Typique : f.Close(), mu.Unlock(), db.Close(), tx.Rollback(), recover().

Arguments évalués immédiatement, exécution reportée

Lorsque vous écrivez defer foo(x), x est évalué au moment de la defer, pas au moment de l'exécution :

Go
x := 10
defer fmt.Println(x)   // cattura 10
x = 99
// quando la funzione ritorna stampa "10", non "99"

## Ordre LIFO

Les reports s'empilent et s'exécutent en commençant par le plus récent :

Go
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
// output: 3, 2, 1

Ceci est cohérent avec la sémantique des ressources : la dernière ouverte est la première être fermé.

defer + recover : gestion de la panique

defer est le seul moyen d'intercepter un panic :

Go
func safe() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("recuperato:", r)
        }
    }()
    panic("boom")
}

Piège : defer en boucle

Mettre defer f.Close() dans une boucle accumule des reports jusqu'à la fin de la fonction, pas de chaque itération. Dans une longue boucle, vous ouvrez de nombreux fichiers et ne les fermez qu'à la sortie de la fonction : risque de fuite du descripteur de fichier.

Go
// MALE: defer accumulati
for _, path := range paths {
    f, _ := os.Open(path)
    defer f.Close()   // chiude TUTTI alla fine della funzione esterna
    // ...
}

// MEGLIO: estrai in una funzione
for _, path := range paths {
    elabora(path)   // ogni chiamata ha il proprio scope di defer
}

Essayez-le

Exercice#go.m3.l5.e1
Tentatives : 0Chargement…

Imprimez 'inizio', puis différez l'impression de 'fine' avec defer, puis imprimez 'mezzo'. La sortie doit être : inizio / mezzo / fine.

Chargement de l'éditeur…
Afficher l'indice

Le defer s'exécute lorsque main() est sur le point de revenir.

Solution disponible après 3 tentatives

Exercice#go.m3.l5.e2
Tentatives : 0Chargement…

Écrivez trois reports consécutifs qui impriment 1, 2 et 3 dans cet ordre dans le code. La sortie sera 3/2/1 (LIFO).

Chargement de l'éditeur…
Afficher l'indice

Trois reports en séquence ; rappelez-vous qu'ils s'exécutent dans l'ordre inverse.

Solution disponible après 3 tentatives

Quiz#go.m3.l5.e3
Prêt

Qu'est-ce que cela imprime ? (remarque : les arguments de report sont évalués immédiatement)

Go
x := 10
defer fmt.Println(x)
x = 99
Options de réponse

Récapitulatif

  • defer call() reporte l'exécution jusqu'au retour de la fonction.
  • Plusieurs reports = ordre LIFO.
  • Arguments évalués immédiatement, exécution reportée.
  • Utilisé pour le nettoyage déterministe : fichiers, mutex, connexions.
  • defer + recover() intercepte un panic (rare, aux frontières).
  • Jamais defer à l'intérieur d'une longue boucle : il s'accumule jusqu'au retour de la fonction externe.