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.
Défi
FacileConstruisons 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
Dividequi 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
SafeDividequi prend deux entiers et retourne à la fois un résultat entier et une erreur. Cette fonction doit :- Utiliser
deferavec 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
Divideen interne - Retourner 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 à partir de l'entrée et utilisezSafeDividepour effectuer le calcul en toute sécurité. Démontrez égalementdeferen affichant des messages de nettoyage dans le bon ordre.Votre fonction principale 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 d'entrée - 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)
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 completeEt avec 10 et 0, votre sortie devrait être :
Starting calculation
Error: calculation error: division by zero
Releasing resources
Cleanup completeAide-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(÷nd)
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
}
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 vs non exportésIntroduction à la POO en GoLes Structs comme ClassesDéfinir des méthodes sur les StructsReceveurs par pointeur vs par valeurInitialisation de StructsFonctions constructeursRécapitulatif - Calculatrice simple4Interfaces
Introduction aux interfacesImplémentation impliciteL'interface comme contratInterface vide (any)Assertion de typeType SwitchComposition d'interfacesInterfaces Stringer & ErrorRécapitulatif - Calculateur de formes7Encapsulation
Champs exportés vs non exportésEncapsulation au niveau du packageMéthodes Getter & SetterMasquage d'informations en GoRécapitulatif - Dossiers étudiants10Génériques (Go 1.18+)
Introduction aux génériquesParamètres de typeContraintes de typeStructures génériquesContournement pour les méthodes génériquesRécapitulatif - Collections génériques13Patrons de conception, Partie 1
Introduction aux Design PatternsPatron SingletonPatron FactoryPatron Abstract FactoryPatron ObserverPatron Strategy2Exploration approfondie des Types et Structs
Types de base et compositesDéfinitions de types personnalisésTags de StructStructs anonymesStructs imbriquéesValeurs par défaut et Zero ValuesRécapitulatif - Carnet de contacts5Composition plutôt qu'héritage
Pourquoi Go n'a pas d'héritageLes bases de l'imbrication de structsPromotion de méthodesImbriquer plusieurs structsImbrication vs AgrégationMasquage de méthodes imbriquéesRécapitulatif - Hiérarchie des employés8Gestion des erreurs & POO
L'interface errorTypes d'erreurs personnalisésError Wrapping (fmt.Errorf)Erreurs sentinelleserrors.Is() et errors.As()Panic, Defer et RecoverRécapitulatif - File Parser11Bibliothèque standard et POO
io.Reader & io.WriterL'interface sort.InterfaceL'interface fmt.Stringerencoding/json avec les StructsL'interface http.HandlerRécapitulatif - Modèles d'API REST14Patrons de conception, Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Template MethodPatron ÉtatPatron CompositeMiddleware en tant que Décorateur3Pointeurs et Mémoire
Bases des pointeurs en GoPointeurs vers des structsPassage par valeur vs référenceLa fonction new()Garbage Collection en GoRécapitulatif - Constructeur de liste chaînée6Le polymorphisme en Go
Le polymorphisme via les interfacesLe Duck Typing en GoRègles de satisfaction des interfacesCollections polymorphesInjection de dépendancesRécapitulatif - Processeur de paiement9Concurrence et POO
Bases des GoroutinesChannels et CommunicationChannels avec buffer vs sans bufferL'instruction Selectsync.Mutex et sync.RWMutexsync.WaitGroupConception de structures Thread-SafeRécapitulatif - Worker Pool