Gestion des erreurs en Go : try/catch et bien plus de A à Z

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 : philosophie et pratique



Contrairement à de nombreux langages modernes, Go (Golang) n'utilise pas la construction classique try/catch. Au lieu de cela, les développeurs Go adhèrent à l'approche « les erreurs comme valeurs » (errors as values). Cela rend le code plus explicite, prévisible et sûr. Dans cet article, nous analyserons tous les aspects de la gestion des erreurs en Go : des modèles de base aux techniques avancées avec defer, panic et recover.



1. Les bases : les erreurs sont simplement des valeurs



En Go, une erreur est une interface error avec une seule méthode Error() string. Toute fonction qui peut échouer retourne une erreur comme dernière valeur de retour.



package main

import ( "errors" "fmt")

// Fonction de division avec retour d'erreurfunc divide(a, b float64) (float64, error) { if b == 0 { return 0, errors.New("division par zéro impossible") } return a / b, nil}

func main() { result, err := divide(10, 0) if err != nil { fmt.Println("Erreur :", err) return } fmt.Println("Résultat :", result)}


Point clé : la vérification if err != nil est la manière standard de gérer les erreurs en Go. Il n'y a pas d'exceptions cachées qui pourraient « surgir » de manière inattendue.



2. Création et personnalisation des erreurs



Go propose plusieurs façons de créer des erreurs :



  • errors.New() — une erreur textuelle simple.
  • fmt.Errorf() — une erreur avec formatage (prend en charge %w pour l'encapsulation).
  • Types personnalisés — pour transmettre un contexte supplémentaire.


Erreur personnalisée avec données supplémentaires



type DivisionError struct {    Dividend float64    Divisor  float64    Message  string}

func (e *DivisionError) Error() string { return fmt.Sprintf("%s : %f / %f", e.Message, e.Dividend, e.Divisor)}

func safeDivide(a, b float64) (float64, error) { if b == 0 { return 0, &DivisionError{ Dividend: a, Divisor: b, Message: "division par zéro", } } return a / b, nil}

func main() { _, err := safeDivide(10, 0) if err != nil { // Assertion de type pour obtenir les champs supplémentaires var divErr *DivisionError if errors.As(err, &divErr) { fmt.Printf("Erreur avec %f sur %f : %s", divErr.Dividend, divErr.Divisor, divErr.Message) } }}


L'utilisation de errors.As() permet de vérifier si une erreur est d'un certain type et d'en extraire les données. C'est l'équivalent de instanceof dans d'autres langages.



3. Modèles de gestion des erreurs : du simple au complexe



En Go, il existe plusieurs modèles établis pour travailler avec les erreurs :



3.1. Sentinel errors (erreurs-sentinelles)

Ce sont des erreurs prédéfinies qui peuvent être comparées avec ==. Exemple : io.EOF.



import (    "errors"    "fmt")

var ErrNotFound = errors.New("élément non trouvé")

func findUser(id int) (string, error) { if id != 1 { return "", ErrNotFound } return "Alice", nil}

func main() { _, err := findUser(2) if errors.Is(err, ErrNotFound) { fmt.Println("Utilisateur non trouvé, création d'un nouveau...") }}


3.2. Encapsulation des erreurs (wrapping)

Depuis Go 1.13, il est possible d'encapsuler les erreurs avec %w dans fmt.Errorf. Cela préserve la chaîne d'erreurs.



func readConfig(path string) error {    data, err := os.ReadFile(path)    if err != nil {        return fmt.Errorf("lecture du fichier de config %s : %w", path, err)    }    // ... traitement de data                

Blogs

Book Recommendations