Historique de la question :
Go se distingue de nombreux langages par son approche de la gestion des erreurs, où les erreurs sont des valeurs et non des exceptions. Ce design a été choisi pour sa transparence et sa simplicité : chaque fois que quelque chose peut mal tourner, la fonction retourne explicitement une erreur comme deuxième valeur de retour.
Problème :
De nombreux débutants essaient d'appliquer au Go les modèles habituels try-catch, se perdent dans un grand nombre de contrôles d'erreur ou n'utilisent pas l'encapsulation des erreurs pour transmettre le contexte. Cela entraîne une perte d'informativité et un débogage difficile.
Solution :
Dans Go, une fonction qui peut retourner une erreur est déclarée comme suit :
func doSomething() (ResultType, error) { // ... if somethingWrong { return nil, errors.New("quelque chose a mal tourné") } return result, nil }
La vérification des erreurs est la responsabilité de l'appelant :
res, err := doSomething() if err != nil { log.Fatalf("échec du processus : %w", err) }
Go 1.13 et versions ultérieures permettent de "wrapper" les erreurs à l'aide de fmt.Errorf("%w", err) pour construire des chaînes d'erreurs. Cela améliore le diagnostic et favorise les meilleures pratiques de description contextuelle des erreurs.
Caractéristiques clés :
Pourquoi créer vos propres types d'erreur, si l'on peut simplement retourner errors.New("...") ?
La bonne réponse : les types d'erreur personnalisés permettent non seulement de communiquer le texte de l'erreur, mais aussi de conserver des informations supplémentaires pour un traitement ultérieur (par exemple, des codes de retour, du contexte), et d'effectuer un traitement plus fin via l'assertion de type.
Exemple :
type NotFoundError struct { Resource string } func (e NotFoundError) Error() string { return fmt.Sprintf("%s non trouvé", e.Resource) } // Vérification if _, ok := err.(NotFoundError); ok { // traitement de l'erreur de recherche }
Est-ce que panic est un bon substitut à l'erreur pour les erreurs critiques ?
Non, panic dans Go est utilisé uniquement dans des situations vraiment désespérées — par exemple, en cas d'erreurs dans le programme lui-même (invariants du programme), mais pas pour des échecs ordinaires (par exemple, impossible d'ouvrir un fichier). Utiliser panic pour signaler des erreurs courantes est mauvais et conduit à un code illisible et ingérable.
Que se passe-t-il si l'on ignore le traitement de l'erreur (err) dans des fonctions imbriquées ?
L'erreur est "perdue", le code continue à s'exécuter, ce qui peut entraîner la propagation d'un état erroné. Il est toujours important de traiter correctement chaque retour d'erreur.
_ = ...Chaque fonction retourne simplement errors.New(...), les erreurs ne sont pas encapsulées, les types d'erreurs sont différents, mais le traitement est toujours le même : elles sont enregistrées et lancées. En conséquence, les fichiers journaux sont remplis de messages non informatifs, il est impossible de les suivre jusqu'à la cause d'origine.
Avantages :
Inconvénients :
Des wrappers d'erreurs sont utilisés via fmt.Errorf("%w", err), des erreurs personnalisées avec des champs utiles, et des vérifications via errors.Is()/errors.As(). Grâce à cela, il est possible de journaliser avec des détails, de séparer les erreurs métier des échecs liés à l'environnement et d'écrire une logique de retry fiable.
Avantages :
Inconvénients :