Go Academy · Leçon

panic, recover et defer

Savoir quand déclencher panic et comment récupérer proprement

Leçon 4 sur 412 étapes

panic, recover et defer est une leçon Go Academy gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Go Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Go Academy comprend 4 leçons au total.

Qu'est-ce que panic ?

panic arrête l'exécution normale de la goroutine actuelle, remonte la pile d'appels en exécutant les fonctions différées et provoque l'arrêt du programme si la panique n'est pas récupérée :

package main
import "fmt"

func mustPositive(n int) int {
    if n <= 0 {
        panic(fmt.Sprintf("mustPositive: got %d", n))
    }
    return n
}

func main() {
    fmt.Println(mustPositive(5))  // 5
    // fmt.Println(mustPositive(-1)) // panics!
}

Quand utiliser panic

Utilisez panic uniquement pour :

  • Les erreurs de programmation véritablement irrécupérables (invariants rompus)
  • Les conditions impossibles qui indiquent un bogue
  • Les échecs au démarrage (configuration manquante, connexions échouées lors de l'initialisation)

N'utilisez jamais panic pour les conditions d'échec attendues — utilisez plutôt error.

Notions de base de defer

defer planifie l'appel d'une fonction au moment où la fonction englobante retourne, quelle que soit la manière dont elle retourne (normalement, avec une erreur ou à la suite d'une panique) :

package main
import "fmt"

func main() {
    defer fmt.Println("third")
    defer fmt.Println("second")  // LIFO order
    defer fmt.Println("first")
    fmt.Println("running...")
    // Output:
    // running...
    // first
    // second
    // third
}

defer pour le nettoyage

L'utilisation la plus courante de defer consiste à garantir le nettoyage des ressources :

package main
import ("fmt"; "os")

func readFile(path string) (string, error) {
    f, err := os.Open(path)
    if err != nil {
        return "", fmt.Errorf("open: %w", err)
    }
    defer f.Close()  // always runs, even if we return early

    buf := make([]byte, 1024)
    n, _ := f.Read(buf)
    return string(buf[:n]), nil
}

recover — intercepter les paniques

recover arrête une panique et retourne sa valeur. Il doit être appelé directement dans une fonction defer :

package main
import "fmt"

func safeDiv(a, b int) (result int, err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("recovered from panic: %v", r)
        }
    }()
    return a / b, nil  // panics if b==0
}

func main() {
    r, err := safeDiv(10, 0)
    fmt.Println(r, err)
    // 0 recovered from panic: runtime error: integer divide by zero
}

recover doit se trouver dans une fonction différée

recover ne fonctionne que s'il est appelé directement dans une fonction différée. Un appel effectué ailleurs retourne nil :

package main
import "fmt"

func wrong() {
    // recover() here does nothing — not in defer
}

func correct() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("caught:", r)
        }
    }()
    panic("oops")
}

func main() { correct() }

panic dans le code de bibliothèque

Le code de bibliothèque ne devrait presque jamais laisser des paniques parvenir aux appelants. Convertissez les paniques en erreurs à la limite de l'API :

package main
import ("fmt"; "runtime/debug")

func safeCall(fn func()) (err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("panic: %v\n%s", r, debug.Stack())
        }
    }()
    fn()
    return nil
}

func main() {
    err := safeCall(func() { panic("boom") })
    fmt.Println(err != nil) // true
}

Ordre LIFO de defer et piège des boucles

Les appels différés s'exécutent dans l'ordre dernier entré, premier sorti (LIFO). Soyez prudent lorsque vous utilisez defer dans des boucles — utilisez une fermeture ou une fonction auxiliaire :

package main
import "fmt"

func processFiles(names []string) {
    for _, name := range names {
        name := name  // capture loop variable
        defer func() { fmt.Println("close:", name) }()
    }
}

func main() {
    processFiles([]string{"a.txt", "b.txt", "c.txt"})
    // Output (LIFO): close: c.txt, close: b.txt, close: a.txt
}

defer avec des valeurs de retour nommées

Les fonctions différées peuvent lire et modifier les valeurs de retour nommées — ce qui est utile pour annoter les erreurs :

package main
import "fmt"

func doWork() (err error) {
    defer func() {
        if err != nil {
            err = fmt.Errorf("doWork: %w", err)
        }
    }()
    return fmt.Errorf("something failed")
}

func main() {
    err := doWork()
    fmt.Println(err) // doWork: something failed
}

panic ou error : guide de décision

Choisir entre panic et error :

  • Utilisez error : échecs attendus (fichier introuvable, délai d'attente du réseau dépassé, entrée invalide)
  • Utilisez panic : erreurs de programmation (accès à une carte nil, accès hors limites), états impossibles, échecs d'initialisation
  • N'utilisez jamais panic au-delà des limites d'une API — les appelants ne peuvent pas le gérer
  • Récupérez les paniques au niveau supérieur des goroutines dans les serveurs pour éviter les arrêts

Vérification rapide

Où faut-il appeler recover() pour intercepter une panique ?

Récapitulatif : panic, recover et defer

Résumé :

  • panic : déroule la pile, exécute les appels différés et fait planter le programme si la panique n’est pas récupérée
  • defer : s’exécute à la sortie d’une fonction (normalement, en cas d’erreur ou de panique), dans l’ordre LIFO
  • recover : arrête la panique et renvoie sa valeur ; doit se trouver dans defer
  • Utilisez panic pour les erreurs de programmation, pas pour les échecs attendus
  • Convertissez les paniques en erreurs aux limites de l’API
Gratuit pour commencer

Apprends Go avec un tuteur IA — gratuit

Écris et exécute du vrai code dans ton navigateur, obtiens de l'aide instantanée d'un tuteur IA disponible 24h/24, et reprends là où tu t'es arrêté sur le web ou dans l'app.

Cours
51
Leçons
203

Questions Fréquemment Posées

La leçon « panic, recover et defer » est-elle gratuite ?

Oui — le texte complet de « panic, recover et defer » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Go Academy, passe à CoddyKit PRO. Le cours Go Academy comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « panic, recover et defer » ?

Savoir quand déclencher panic et comment récupérer proprement Tu pratiques Go Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer Go Academy ?

Aucune expérience préalable n'est requise. Go Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.

Combien de temps prend la leçon « panic, recover et defer » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon Go Academy ?

Oui. Chaque leçon Go Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. L’interface error
  2. Créer des erreurs personnalisées
  3. Encapsuler et désencapsuler les erreurs
  4. panic, recover et defer
← Retour à Go Academy