Menu
Coddy logo textTech

Erreurs sentinelles

Fait partie de la section Programmation Orientée Objet du Journey GO de Coddy — leçon 55 sur 107.

Une erreur sentinelle est une variable d'erreur prédéfinie au niveau du package qui représente une condition d'erreur spécifique. Contrairement à la création de nouvelles erreurs à chaque fois avec errors.New, les erreurs sentinelles sont déclarées une seule fois et réutilisées dans tout votre code.

Vous définissez les erreurs sentinelles comme des variables au niveau du package, généralement avec des noms commençant par Err :

package user

import "errors"

var (
    ErrNotFound     = errors.New("user not found")
    ErrInvalidEmail = errors.New("invalid email address")
    ErrDuplicate    = errors.New("user already exists")
)

Les fonctions renvoient ces erreurs prédéfinies lorsque des conditions spécifiques surviennent :

func FindUser(id int) (*User, error) {
    user, exists := users[id]
    if !exists {
        return nil, ErrNotFound
    }
    return user, nil
}

La puissance des erreurs sentinelles réside dans le fait que les appelants peuvent vérifier des conditions d'erreur spécifiques en comparant directement les valeurs d'erreur :

user, err := FindUser(42)
if err == ErrNotFound {
    fmt.Println("Creating new user...")
} else if err != nil {
    fmt.Println("Unexpected error:", err)
}

La bibliothèque standard de Go utilise intensivement les erreurs sentinelles. Par exemple, io.EOF signale la fin de l'entrée, et sql.ErrNoRows indique un résultat de requête vide. Ce modèle crée un contrat clair entre les packages et leurs utilisateurs sur les erreurs à attendre.

Cependant, les vérifications d'égalité simples échouent lorsque les erreurs sont enveloppées. Dans la prochaine leçon, vous apprendrez comment errors.Is() résout ce problème en vérifiant toute la chaîne d'erreurs.

challenge icon

Défi

Facile

Construisons un système de gestion d'inventaire qui utilise des erreurs sentinelles pour communiquer des conditions d'échec spécifiques. Vous définirez des variables d'erreur au niveau du package que les appelants pourront vérifier pour gérer différents scénarios de manière appropriée.

Vous organiserez votre code sur deux fichiers :

  • inventory.go : Créez un système d'inventaire avec des erreurs sentinelles prédéfinies pour les cas d'échec courants.

    Définissez trois erreurs sentinelles au niveau du package :

    • ErrItemNotFound avec le message "item not found in inventory"
    • ErrOutOfStock avec le message "item is out of stock"
    • ErrInsufficientQuantity avec le message "insufficient quantity available"

    Créez une structure Inventory qui contient une map associant des noms d'articles à leurs quantités. Implémentez ces méthodes :

    • NewInventory() *Inventory - crée un inventaire vide
    • AddItem(name string, quantity int) - ajoute ou met à jour la quantité d'un article
    • GetQuantity(name string) (int, error) - retourne la quantité d'un article, ou ErrItemNotFound s'il n'existe pas
    • Purchase(name string, quantity int) error - tente d'acheter des articles. Retourne ErrItemNotFound si l'article n'existe pas, ErrOutOfStock si la quantité actuelle est de zéro, ou ErrInsufficientQuantity si la quantité demandée dépasse le stock disponible. En cas de succès, réduisez l'inventaire et retournez nil.
  • main.go : Lisez les opérations d'inventaire depuis l'entrée et démontrez comment les appelants peuvent vérifier des erreurs sentinelles spécifiques en utilisant une comparaison d'égalité directe.

    Lisez le nom de l'article et la quantité d'achat depuis l'entrée. Créez un inventaire, ajoutez l'article "laptop" avec une quantité de 5, puis tentez l'achat. En fonction de l'erreur retournée, affichez un message spécifique montrant que vous avez identifié quelle erreur sentinelle s'est produite.

Les entrées suivantes seront fournies :

  • Ligne 1 : Nom de l'article à acheter
  • Ligne 2 : Quantité à acheter

Gérez le résultat en vérifiant quelle erreur spécifique a été retournée :

  • Si err == ErrItemNotFound : affichez Error: Item '[name]' does not exist in our inventory
  • Si err == ErrOutOfStock : affichez Error: Item '[name]' is currently out of stock
  • Si err == ErrInsufficientQuantity : affichez Error: Cannot purchase [quantity] units of '[name]' - not enough in stock
  • En cas de succès : affichez Successfully purchased [quantity] units of '[name]'

Par exemple, avec laptop et 3, votre sortie devrait être :

Successfully purchased 3 units of 'laptop'

Et avec phone et 2, votre sortie devrait être :

Error: Item 'phone' does not exist in our inventory

Et avec laptop et 10, votre sortie devrait être :

Error: Cannot purchase 10 units of 'laptop' - not enough in stock

Aide-mémoire

Une erreur sentinelle est une variable d'erreur prédéfinie au niveau du package qui représente une condition d'erreur spécifique. Les erreurs sentinelles sont déclarées une seule fois et réutilisées dans tout votre code.

Définissez les erreurs sentinelles comme des variables au niveau du package, généralement avec des noms commençant par Err :

package user

import "errors"

var (
    ErrNotFound     = errors.New("user not found")
    ErrInvalidEmail = errors.New("invalid email address")
    ErrDuplicate    = errors.New("user already exists")
)

Les fonctions renvoient ces erreurs prédéfinies lorsque des conditions spécifiques surviennent :

func FindUser(id int) (*User, error) {
    user, exists := users[id]
    if !exists {
        return nil, ErrNotFound
    }
    return user, nil
}

Les appelants peuvent vérifier des conditions d'erreur spécifiques en comparant directement les valeurs d'erreur :

user, err := FindUser(42)
if err == ErrNotFound {
    fmt.Println("Creating new user...")
} else if err != nil {
    fmt.Println("Unexpected error:", err)
}

La bibliothèque standard de Go utilise largement les erreurs sentinelles, telles que io.EOF et sql.ErrNoRows.

Essayez vous-même

package main

import (
	"fmt"
)

func main() {
	// Lire l'entrée
	var itemName string
	var quantity int
	fmt.Scanln(&itemName)
	fmt.Scanln(&quantity)

	// Créer l'inventaire et ajouter "laptop" avec une quantité de 5
	inv := NewInventory()
	inv.AddItem("laptop", 5)

	// TODO: Tenter d'acheter l'article
	// Appeler inv.Purchase(itemName, quantity)

	// TODO: Vérifier quelle erreur sentinelle spécifique a été retournée en utilisant une comparaison d'égalité directe
	// Utiliser des instructions if/else if pour vérifier :
	// - err == ErrItemNotFound
	// - err == ErrOutOfStock
	// - err == ErrInsufficientQuantity
	// - err == nil (succès)

	// TODO: Afficher le message approprié en fonction de l'erreur
	// Si ErrItemNotFound: fmt.Printf("Error: Item '%s' does not exist in our inventory\n", itemName)
	// Si ErrOutOfStock: fmt.Printf("Error: Item '%s' is currently out of stock\n", itemName)
	// Si ErrInsufficientQuantity: fmt.Printf("Error: Cannot purchase %d units of '%s' - not enough in stock\n", quantity, itemName)
	// Si succès: fmt.Printf("Successfully purchased %d units of '%s'\n", quantity, itemName)
}
quiz iconTestez-vous

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