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.
Défi
FacileConstruisons 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
Dividequi 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
SafeDividequi prend deux entiers et renvoie à la fois un résultat entier et une erreur. Cette fonction doit :- Utiliser
deferavec 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
Divideen interne - Renvoyer le résultat et
nilen cas de succès, ou zéro et l’erreur si une panique a été récupérée
- Utiliser
main.go: lisez deux entiers en entrée et utilisezSafeDividepour effectuer le calcul en toute sécurité. Montrez égalementdeferen affichant les messages de nettoyage dans le bon ordre.Votre fonction main doit :
- Afficher
Starting calculationau début - Utiliser
deferpour planifier l’affichage deCleanup complete - Utiliser un autre
deferpour planifier l’affichage deReleasing resources - Appeler
SafeDivideavec les valeurs saisies - Afficher soit
Result: [value], soitError: [error message]selon le résultat
- Afficher
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 completeEt avec 10 et 0, votre sortie doit être :
Starting calculation
Error: calculation error: division by zero
Releasing resources
Cleanup completeEssayez vous-même
package main
import (
"fmt"
)
func main() {
// Lire l'entrée
var dividend, divisor int
fmt.Scanln(÷nd)
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
}
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
1Fondamentaux de la POO en Go
Fichiers externesEspace de travail et modules GoPackages et importsNoms exportés et non exportésIntroduction à la POO en GoStructs comme classesDéfinir des méthodes sur des structsRécepteurs pointeurs ou par valeurInitialisation des structsFonctions constructeursRécapitulatif - Calculatrice simple4Interfaces
Introduction aux interfacesImplémentation impliciteL’interface comme contratInterface vide (any)Assertion de typeCommutation de typeComposition d’interfacesInterfaces Stringer et ErrorRécapitulatif - Calculateur de formes7Encapsulation
Champs exportés vs non exportésEncapsulation au niveau du packageMéthodes Getter et SetterDissimulation de l’information en GoRécapitulatif – Fiches d’étudiants10Génériques (Go 1.18+)
Introduction aux génériquesParamètres de typeContraintes de typeStructures génériquesSolution de contournement pour les méthodes génériquesRécapitulatif - Collection générique2Plongée approfondie dans les types et les structs
Types de base et compositesDéfinitions de types personnalisésTags de structStructs anonymesStructs imbriquésValeurs zéro et valeurs par défautRécapitulatif - Carnet de contacts5La composition plutôt que l’héritage
Pourquoi Go n’a pas d’héritageBases de l’inclusion de structsPromotion des méthodesInclure plusieurs structsInclusion ou agrégationMasquage des méthodes inclusesRécapitulatif : hiérarchie des employés8Gestion des erreurs et POO
L’interface errorTypes d’erreurs personnalisésEnrobage des erreurs (fmt.Errorf)Erreurs sentinelleserrors.Is() et errors.As()Panic, Defer et RecoverRécapitulatif - Analyseur de fichiers11Bibliothèque standard et POO
io.Reader et io.Writersort.InterfaceInterface fmt.Stringerencoding/json avec des structsInterface http.HandlerRécapitulatif - Modèles d’API REST14Modèles de conception – Partie 2
Modèle CommandeModèle AdaptateurModèle DécorateurModèle Méthode modèleModèle ÉtatModèle CompositeMiddleware comme décorateur3Pointeurs et mémoire
Notions de base des pointeurs en GoPointeurs vers des structuresPassage par valeur ou par référenceLa fonction new()Garbage collection en GoRécapitulatif - Constructeur de listes chaînées6Polymorphisme en Go
Polymorphisme via les interfacesDuck typing en GoRègles de satisfaction des interfacesCollections polymorphesInjection de dépendancesRécapitulatif – Processeur de paiements9Concurrence et POO
Bases des GoroutinesCanaux et communicationCanaux tamponnés ou non tamponnésInstruction selectsync.Mutex et sync.RWMutexsync.WaitGroupConception de structures thread-safeRécapitulatif - Pool de workersEntraînez-vous par vous-même : Compilateur Go en ligne