Go Academy · Leçon

Encapsuler et désencapsuler les erreurs

Utiliser %w, errors.Is et errors.As

Leçon 3 sur 412 étapes

Encapsuler et désencapsuler les erreurs est une leçon Go Academy gratuite sur CoddyKit. Ceci est la leçon 3 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Go Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Go Academy comprend 4 leçons au total.

Qu'est-ce que l'encapsulation des erreurs ?

L'encapsulation des erreurs intègre une erreur originale dans une nouvelle erreur, en préservant l'originale pour l'inspection programmatique tout en ajoutant un contexte. Cette fonctionnalité a été correctement introduite dans Go 1.13 :

package main
import ("fmt"; "errors")

var ErrDB = errors.New("database unreachable")

func queryUsers() error {
    return fmt.Errorf("queryUsers: %w", ErrDB)
}

func loadProfile(id int) error {
    return fmt.Errorf("loadProfile(%d): %w", id, queryUsers())
}

func main() {
    err := loadProfile(42)
    fmt.Println(err) // loadProfile(42): queryUsers: database unreachable
}

Le verbe %w

Utilisez %w (et non %v) dans fmt.Errorf pour encapsuler une erreur. L'erreur encapsulée est accessible via errors.Unwrap :

package main
import ("fmt"; "errors")

func main() {
    inner := errors.New("inner error")
    outer := fmt.Errorf("outer: %w", inner)

    fmt.Println(outer)              // outer: inner error
    fmt.Println(errors.Unwrap(outer)) // inner error
    fmt.Println(errors.Is(outer, inner)) // true
}

errors.Unwrap

errors.Unwrap retourne l'erreur suivante dans la chaîne (l'erreur encapsulée), ou nil s'il n'y en a aucune :

package main
import ("fmt"; "errors")

type Layer struct{ msg string; err error }
func (l *Layer) Error() string { return l.msg }
func (l *Layer) Unwrap() error { return l.err }

func main() {
    root := errors.New("root")
    mid  := &Layer{"mid", root}
    top  := &Layer{"top", mid}

    fmt.Println(errors.Unwrap(top))  // mid
    fmt.Println(errors.Unwrap(mid))  // root
    fmt.Println(errors.Unwrap(root)) // <nil>
}

errors.Is — parcours de la chaîne

errors.Is(err, target) désencapsule récursivement la chaîne d'erreurs jusqu'à trouver une correspondance ou atteindre nil :

package main
import ("fmt"; "errors")

var ErrNotFound = errors.New("not found")

func findItem(id int) error {
    return fmt.Errorf("findItem(%d): %w",
        id, fmt.Errorf("repo: %w", ErrNotFound))
}

func main() {
    err := findItem(7)
    fmt.Println(errors.Is(err, ErrNotFound)) // true — deep in chain
    fmt.Println(err)                         // full message chain
}

errors.As — parcours de la chaîne pour les types

errors.As(err, &target) parcourt la chaîne à la recherche d'une erreur affectable au type de la cible :

package main
import ("fmt"; "errors")

type StatusError struct{ Code int }
func (e *StatusError) Error() string { return fmt.Sprintf("status %d", e.Code) }

func doRequest() error {
    return fmt.Errorf("request: %w", &StatusError{503})
}

func main() {
    err := doRequest()
    var se *StatusError
    if errors.As(err, &se) {
        fmt.Println("status code:", se.Code) // 503
    }
}

Unwrap personnalisé pour les chaînes

Implémentez Unwrap() error sur votre type d'erreur personnalisé pour prendre en charge errors.Is et errors.As :

package main
import ("fmt"; "errors")

type AppError struct {
    Op  string
    Err error
}
func (e *AppError) Error() string  { return fmt.Sprintf("%s: %v", e.Op, e.Err) }
func (e *AppError) Unwrap() error  { return e.Err }

var ErrAuth = errors.New("unauthorized")

func main() {
    err := &AppError{"login", ErrAuth}
    fmt.Println(errors.Is(err, ErrAuth)) // true
}

%v ou %w dans fmt.Errorf

La différence entre %v et %w :

package main
import ("fmt"; "errors")

func main() {
    inner := errors.New("inner")

    withV := fmt.Errorf("outer: %v", inner) // string only, no wrap
    withW := fmt.Errorf("outer: %w", inner) // wraps inner

    fmt.Println(errors.Is(withV, inner)) // false — not wrapped
    fmt.Println(errors.Is(withW, inner)) // true  — wrapped
}

L'encapsulation en pratique : gestionnaire HTTP

Une encapsulation cohérente des erreurs facilite le débogage dans les systèmes en production :

package main
import "fmt"

func dbQuery(sql string) error {
    return fmt.Errorf("db.Query(%q): connection refused", sql)
}

func getUserByID(id int) (string, error) {
    if err := dbQuery("SELECT * FROM users WHERE id=?"); err != nil {
        return "", fmt.Errorf("getUserByID(%d): %w", id, err)
    }
    return "Alice", nil
}

func handler() error {
    _, err := getUserByID(1)
    if err != nil {
        return fmt.Errorf("handler: %w", err)
    }
    return nil
}

func main() { fmt.Println(handler()) }

errors.Join — encapsulations multiples (Go 1.20 et versions ultérieures)

errors.Join crée une erreur qui encapsule plusieurs erreurs. errors.Is les vérifie toutes :

package main
import ("fmt"; "errors")

var ErrA = errors.New("err A")
var ErrB = errors.New("err B")

func main() {
    joined := errors.Join(ErrA, ErrB)
    fmt.Println(joined)
    fmt.Println(errors.Is(joined, ErrA)) // true
    fmt.Println(errors.Is(joined, ErrB)) // true
}

Bonnes pratiques de désencapsulation

Recommandations pour l'encapsulation des erreurs :

  • Encapsulez avec %w pour préserver l'erreur et permettre son inspection programmatique
  • Ajoutez le nom de l'opération comme contexte : fmt.Errorf("funcName: %w", err)
  • N'encapsulez pas les erreurs sentinelles si les appelants n'utilisent pas errors.Is
  • Évitez d'encapsuler deux fois le même contexte à chaque niveau
  • Implémentez Unwrap() sur les types personnalisés pour participer aux chaînes

Vérification rapide

Quelle est la différence entre l'utilisation de %v et de %w dans fmt.Errorf ?

Récapitulatif : encapsulation et désencapsulation des erreurs

Résumé :

  • fmt.Errorf("ctx: %w", err) encapsule avec un contexte
  • errors.Unwrap récupère l'erreur suivante dans la chaîne
  • errors.Is parcourt la chaîne à la recherche d'une correspondance d'identité
  • errors.As parcourt la chaîne à la recherche d'une correspondance de type
  • Les types personnalisés implémentent Unwrap() error
  • errors.Join encapsule plusieurs erreurs (Go 1.20 et versions ultérieures)
Gratuit pour commencer

Apprends Go avec un tuteur IA — gratuit

Écris et exécute du vrai code dans ton navigateur, obtiens de l'aide instantanée d'un tuteur IA disponible 24h/24, et reprends là où tu t'es arrêté sur le web ou dans l'app.

Cours
51
Leçons
203

Questions Fréquemment Posées

La leçon « Encapsuler et désencapsuler les erreurs » est-elle gratuite ?

Oui — le texte complet de « Encapsuler et désencapsuler les erreurs » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Go Academy, passe à CoddyKit PRO. Le cours Go Academy comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Encapsuler et désencapsuler les erreurs » ?

Utiliser %w, errors.Is et errors.As Tu pratiques Go Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer Go Academy ?

Aucune expérience préalable n'est requise. Go Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 3 sur 4.

Combien de temps prend la leçon « Encapsuler et désencapsuler les erreurs » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon Go Academy ?

Oui. Chaque leçon Go Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. L’interface error
  2. Créer des erreurs personnalisées
  3. Encapsuler et désencapsuler les erreurs
  4. panic, recover et defer
← Retour à Go Academy