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.

Bien que Go mette l’accent sur le renvoi d’erreurs, certaines situations sont véritablement irrécupérables. Pour ces cas, Go fournit panic, defer et recover : un mécanisme de gestion des 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 aux 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 englobante se termine, que ce soit normalement ou en raison d’une panique. 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 rétablit 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 une panique en erreur ordinaire, ce qui permet à votre programme de continuer. Utilisez-le avec parcimonie : préférez renvoyer des erreurs pour les cas d’échec prévisibles et réservez panic/recover aux situations véritablement exceptionnelles, comme un état corrompu ou des conditions irrécupérables.

challenge icon

Défi

Facile

Construisons une calculatrice de division sûre qui montre comment utiliser panic, defer et recover pour gérer élégamment les situations exceptionnelles. Votre calculatrice tentera des opérations risquées et convertira les paniques en erreurs ordinaires pouvant être gérées normalement.

Vous organiserez votre code sur deux fichiers :

  • calculator.go : créez la logique de division avec récupération des paniques.

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

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

    • Utiliser defer avec une fonction anonyme pour récupérer toute panique
    • Si une panique est récupérée, la convertir en erreur avec le format "calculation error: [panic message]"
    • Appeler la fonction Divide en interne
    • Renvoyer 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 en entrée et utilisez SafeDivide pour effectuer le calcul en toute sécurité. Montrez également defer en affichant les messages de nettoyage dans le bon ordre.

    Votre fonction main 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 saisies
    • 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)

N’oubliez pas 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 dans lequel ils ont été différés.

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

Starting calculation
Result: 5
Releasing resources
Cleanup complete

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

Starting calculation
Error: calculation error: division by zero
Releasing resources
Cleanup complete
FORMAT DE SORTIE REQUIS : [Votre contenu traduit ici]

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émarrage
	fmt.Println("Starting calculation")

	// TODO: Use defer to schedule "Cleanup complete" message

	// TODO: Use defer to schedule "Releasing resources" message
	// Souvenez-vous : les appels différés s'exécutent dans l'ordre LIFO (last-in, first-out)

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

	// TODO: Affichez soit "Result: [value]" soit "Error: [error message]"
	// selon qu'une erreur a été renvoyé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

Entraînez-vous par vous-même : Compilateur Go en ligne