Menu
Coddy logo textTech

Panic, Defer et Recover

Fait partie de la section Programmation Orientée Objet du Journey GO de Coddy — leçon 57 sur 107.

Alors que Go met l'accent sur le retour d'erreurs, certaines situations sont véritablement irrécupérables. Pour ces cas, Go fournit panic, defer et recover — un mécanisme pour gérer les circonstances exceptionnelles.

panic arrête immédiatement l'exécution normale. Il est réservé aux erreurs de programmation comme l'accès à un index hors limites, et non pour les erreurs attendues comme une saisie utilisateur invalide :

func MustGetConfig(key string) string {
    value, exists := config[key]
    if !exists {
        panic("missing required config: " + key)
    }
    return value
}

defer planifie l'exécution d'une fonction lorsque la fonction environnante se termine — que ce soit normalement ou à cause d'un panic. Les appels différés s'exécutent dans l'ordre inverse (dernier entré, premier sorti) :

func ProcessFile() {
    fmt.Println("Opening file")
    defer fmt.Println("Closing file")
    fmt.Println("Processing...")
    // Sortie : Opening file, Processing..., Closing file
}

recover intercepte une panique et reprend l'exécution normale. Elle ne fonctionne qu'à l'intérieur d'une fonction différée :

func SafeOperation() (err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("recovered from panic: %v", r)
        }
    }()
    
    riskyOperation()
    return nil
}

Ce modèle convertit un panic en une erreur classique, permettant à votre programme de continuer. Utilisez-le avec parcimonie — préférez renvoyer des erreurs pour les cas d'échec attendus, et réservez panic/recover pour les situations véritablement exceptionnelles comme un état corrompu ou des conditions irrécupérables.

challenge icon

Défi

Facile

Construisons un calculateur de division sécurisé qui démontre comment utiliser panic, defer, et recover pour gérer les situations exceptionnelles avec élégance. Votre calculateur tentera des opérations risquées et convertira les paniques en erreurs régulières pouvant être traitées normalement.

Vous organiserez votre code sur deux fichiers :

  • calculator.go : Créez la logique de division avec récupération de panique.

    Implémentez une fonction Divide qui prend deux entiers et panique avec le message "division by zero" si le diviseur est zéro. Sinon, elle retourne le résultat entier de la division.

    Implémentez une fonction SafeDivide qui prend deux entiers et retourne à la fois un résultat entier et une erreur. Cette fonction doit :

    • Utiliser defer avec une fonction anonyme pour récupérer de toute panique
    • Si une panique est récupérée, la convertir en une erreur avec le format "calculation error: [panic message]"
    • Appeler la fonction Divide en interne
    • Retourner le résultat et nil en cas de succès, ou zéro et l'erreur si une panique a été récupérée
  • main.go : Lisez deux entiers à partir de l'entrée et utilisez SafeDivide pour effectuer le calcul en toute sécurité. Démontrez également defer en affichant des messages de nettoyage dans le bon ordre.

    Votre fonction principale doit :

    • Afficher Starting calculation au début
    • Utiliser defer pour planifier l'affichage de Cleanup complete
    • Utiliser un autre defer pour planifier l'affichage de Releasing resources
    • Appeler SafeDivide avec les valeurs d'entrée
    • Afficher soit Result: [value] soit Error: [error message] selon le résultat

Les entrées suivantes seront fournies :

  • Ligne 1 : Premier entier (dividende)
  • Ligne 2 : Deuxième entier (diviseur)

Rappelez-vous que les appels différés s'exécutent dans l'ordre inverse (dernier entré, premier sorti), de sorte que vos messages de nettoyage doivent apparaître dans l'ordre opposé à celui où ils ont été différés.

Par exemple, avec 20 et 4, votre sortie devrait être :

Starting calculation
Result: 5
Releasing resources
Cleanup complete

Et avec 10 et 0, votre sortie devrait être :

Starting calculation
Error: calculation error: division by zero
Releasing resources
Cleanup complete

Aide-mémoire

Go fournit panic, defer, et recover pour gérer les circonstances exceptionnelles.

panic arrête immédiatement l'exécution normale et est réservé aux erreurs de programmation irrécupérables :

func MustGetConfig(key string) string {
    value, exists := config[key]
    if !exists {
        panic("missing required config: " + key)
    }
    return value
}

defer planifie l'exécution d'une fonction lorsque la fonction parente se termine. Les appels différés s'exécutent dans l'ordre inverse (dernier entré, premier sorti) :

func ProcessFile() {
    fmt.Println("Opening file")
    defer fmt.Println("Closing file")
    fmt.Println("Processing...")
    // Sortie : Opening file, Processing..., Closing file
}

recover intercepte un panic et reprend l'exécution normale. Il ne fonctionne qu'à l'intérieur d'une fonction différée :

func SafeOperation() (err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("recovered from panic: %v", r)
        }
    }()
    
    riskyOperation()
    return nil
}

Ce modèle convertit un panic en une erreur classique. Privilégiez le retour d'erreurs pour les échecs attendus, et réservez panic/recover pour les situations véritablement exceptionnelles.

Essayez vous-même

package main

import (
	"fmt"
)

func main() {
	// Lire l'entrée
	var dividend, divisor int
	fmt.Scanln(&dividend)
	fmt.Scanln(&divisor)

	// Afficher le message de début
	fmt.Println("Starting calculation")

	// TODO: Utiliser defer pour planifier le message "Cleanup complete"

	// TODO: Utiliser defer pour planifier le message "Releasing resources"
	// Rappel : les appels différés s'exécutent dans l'ordre LIFO (dernier entré, premier sorti)

	// TODO: Appeler SafeDivide avec les valeurs d'entrée

	// TODO: Afficher soit "Result: [value]" soit "Error: [error message]"
	// selon si une erreur a été retournée ou non
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet