Gestion des erreurs en Go : try/catch et au-delà — niveau avancé

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Gestion des erreurs en Go : try/catch et au-delà — niveau avancé

\n\n

Contrairement à de nombreux langages modernes (Java, Python, JavaScript), Go ne dispose pas des constructions traditionnelles try/catch/finally. Les développeurs venant d'autres écosystèmes perçoivent souvent cela comme un défaut. Cependant, la philosophie de Go propose une manière plus explicite et prévisible de travailler avec les erreurs. Dans cet article, nous analyserons les techniques avancées de gestion des erreurs en Go : des principes de base à la création de systèmes flexibles avec panic/recover, l'encapsulation des erreurs et les types personnalisés.

\n\n

1. Pourquoi Go n'a-t-il pas de try/catch ?

\n\n

La raison principale est la simplicité et la lisibilité du code. En Go, une erreur est simplement une valeur (error) que la fonction retourne comme dernier résultat. Le développeur vérifie explicitement cette valeur, plutôt que de compter sur un flux d'exceptions caché. Cela rend le flux d'exécution du programme évident.

\n\n

Le modèle standard ressemble à ceci :

\n\n
package main\n\nimport (\n    "fmt"\n    "os"\n)\n\nfunc readFile(name string) ([]byte, error) {\n    data, err := os.ReadFile(name)\n    if err != nil {\n        return nil, fmt.Errorf("impossible de lire le fichier %s : %w", name, err)\n    }\n    return data, nil\n}\n\nfunc main() {\n    data, err := readFile("config.json")\n    if err != nil {\n        fmt.Println("Erreur :", err)\n        return\n    }\n    fmt.Println("Données :", string(data))\n}
\n\n

Ici, chaque erreur potentielle est traitée explicitement. Ce n'est pas du « bruit », mais une garantie que le programmeur a envisagé une éventuelle défaillance.

\n\n

2. Techniques avancées : encapsulations et chaînes d'erreurs

\n\n

Go 1.13 a introduit la prise en charge de l'encapsulation des erreurs via %w dans fmt.Errorf. Cela permet de créer des chaînes d'erreurs tout en conservant la cause d'origine. Pour déballer ces chaînes, on utilise les fonctions errors.Is et errors.As.

\n\n

Exemple d'encapsulation et de vérification :

\n\n
package main\n\nimport (\n    "errors"\n    "fmt"\n)\n\nvar ErrNotFound = errors.New("enregistrement non trouvé")\n\nfunc findUser(id int) (string, error) {\n    if id != 42 {\n        return "", fmt.Errorf("recherche utilisateur %d : %w", id, ErrNotFound)\n    }\n    return "Alice", nil\n}\n\nfunc main() {\n    _, err := findUser(100)\n    if errors.Is(err, ErrNotFound) {\n        fmt.Println("Erreur : enregistrement absent. Détail :", err)\n    } else {\n        fmt.Println("Erreur inconnue :", err)\n    }\n}
\n\n

Utilisation de errors.As pour les erreurs typées :

\n\n
package main\n\nimport (\n    "errors"\n    "fmt"\n)\n\ntype ValidationError struct {\n    Field string\n    Msg   string\n}\n\nfunc (e *ValidationError) Error() string {\n    return fmt.Sprintf("erreur de validation du champ %s : %s", e.Field, e.Msg)\n}\n\nfunc validateAge(age int) error {\n    if age < 0 {\n        return &ValidationError{Field: "age", Msg: "l'âge ne peut pas être négatif"}\n    }\n    return nil\n}\n\nfunc main() {\n    err := validateAge(-5)\n    var ve *ValidationError\n    if errors.As(err, &ve) {\n        fmt.Printf("Champ : %s, Message : %s\\n", ve.Field, ve.Msg)\n    } else {\n        fmt.Println("Erreur inconnue :", err)\n    }\n}
\n\n

3. Panic et Recover : récupération d'urgence

\n\n

Bien que panic en Go soit l'équivalent d'une exception, il ne doit être utilisé que pour des situations véritablement exceptionnelles (par exemple, une erreur logique du programmeur, une division par zéro, un dépassement de limites de tableau). recover permet d'intercepter la panique et de reprendre l'exécution.

\n\n

Important : recover ne fonctionne qu'à l'intérieur d'une fonction différée (defer). Un scénario typique est un middleware dans un serveur HTTP ou la protection d'une goroutine.

\n\n

Exemple de lancement sécurisé d'une goroutine :

\n\n
package main\n\nimport (\n    "fmt"\n    "time"\n)\n\nfunc safeGoroutine(fn func()) {\n    go func() {\n                

Blogs

Book Recommendations