Gestion des erreurs en Go
Le langage Go fournit un mécanisme de gestion des erreurs très simple via son interface error intégrée.
La gestion des erreurs de Go utilise une approche de retour d'erreur explicite plutôt qu'un mécanisme traditionnel de gestion des exceptions. Cette conception rend la logique du code plus claire et permet aux développeurs de gérer plus facilement les erreurs explicitement pendant la compilation ou l'exécution.
La gestion des erreurs de Go repose principalement sur les mécanismes suivants :
errorinterfaceLa représentation standard de l'erreur.- Valeur de retour expliciteLes erreurs sont renvoyées via la valeur de retour de la fonction.
- Erreur personnalisée: Les erreurs peuvent être créées via la bibliothèque standard ou de manière personnalisée.
panicetrecoverGérer les erreurs fatales irrécupérables.
interface error
La bibliothèque standard Go définit une interface error, représentant une abstraction d'une erreur.
Le type error est un type interface. Voici sa définition :
type error interface {
Error() string
}
- Implémentation
errorinterface: Tout ce qui implémenteError()Tout type qui implémente la méthode Error() peut être utilisé comme une erreur. Error()La méthode retourne une chaîne décrivant l'erreur.
Utiliser le package errors pour créer des erreurs
En programmation, nous pouvons générer des informations d'erreur en implémentant le type interface error.
Créer une erreur simple :
Exemple
import (
"errors"
"fmt"
)
func main() {
err := errors.New("this is an error")
fmt.Println(err) // Sortie : this is an error
}
Les fonctions renvoient généralement les informations d'erreur comme dernière valeur de retour. Vous pouvez utiliser errors.New pour renvoyer un message d'erreur :
func Sqrt(f float64) (float64, error) {
if f < 0 {
return 0, errors.New("math: square root of negative number")
}
// 实现
}
Dans l'exemple suivant, nous passons un nombre négatif à Sqrt, puis obtenons un objet d'erreur non nil. La comparaison de cet objet avec nil renvoie true, donc fmt.Println est appelé pour afficher l'erreur (lorsque le package fmt gère une erreur, il appelle la méthode Error). Voir le code d'appel d'exemple ci-dessous :
result, err:= Sqrt(-1)
if err != nil {
fmt.Println(err)
}
Renvoyer explicitement des erreurs
En Go, les erreurs sont généralement renvoyées comme valeurs de retour des fonctions, et les développeurs doivent les vérifier et les gérer explicitement.
Renvoyer explicitement des erreurs :
Exemple
import (
"errors"
"fmt"
)
func divide(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}
func main() {
result, err := divide(10, 0)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println("Result:", result)
}
}
Sortie :
Error: division by zero
Erreur personnalisée
En définissant des types personnalisés, vous pouvez étendre l'interface error.
Types d'erreur personnalisés :
Exemple
import (
"fmt"
)
type DivideError struct {
Dividend int
Divisor int
}
func (e *DivideError) Error() string {
return fmt.Sprintf("cannot divide %d by %d", e.Dividend, e.Divisor)
}
func divide(a, b int) (int, error) {
if b == 0 {
return 0, &DivideError{Dividend: a, Divisor: b}
}
return a / b, nil
}
func main() {
_, err := divide(10, 0)
if err != nil {
fmt.Println(err) // Sortie : cannot divide 10 by 0
}
}
Le package fmt et le formatage des erreurs.
fmtLe package fournit une prise en charge de la sortie formatée pour les erreurs :
%v: Format par défaut.%+v: Si pris en charge, afficher les informations détaillées sur l'erreur.%sSortie sous forme de chaîne.
Exemple
import (
"fmt"
)
// Définir une struct DivideError
type DivideError struct {
dividee int
divider int
}
// Implémenter l'interface `error`
func (de *DivideError) Error() string {
strFormat := `
Impossible de continuer, le diviseur est zéro.
dividee: %d
divider: 0
`
return fmt.Sprintf(strFormat, de.dividee)
}
// Définir une fonction pour la division de type `int`
func Divide(varDividee int, varDivider int) (result int, errorMsg string) {
if varDivider == 0 {
dData := DivideError{
dividee: varDividee,
divider: varDivider,
}
errorMsg = dData.Error()
return
} else {
return varDividee / varDivider, ""
}
}
func main() {
// Cas normal
if result, errorMsg := Divide(100, 10); errorMsg == "" {
fmt.Println("100/10 = ", result)
}
// Renvoie un message d'erreur lorsque le diviseur est zéro
if _, errorMsg := Divide(100, 0); errorMsg != "" {
fmt.Println("errorMsg is: ", errorMsg)
}
}
Exécutez le programme ci-dessus, la sortie est :
100/10 = 10
errorMsg is:
Cannot proceed, the divider is zero.
dividee: 100
divider: 0
Utilisation de errors.Is et errors.As
À partir de Go 1.13,errorsLe paquet introduiterrors.Iseterrors.AsUtilisé pour gérer les chaînes d'erreurs :
errors.Is
Vérifie si une erreur est une erreur spécifique ou a été enveloppée à partir de cette erreur.
Exemple
import (
"errors"
"fmt"
)
var ErrNotFound = errors.New("not found")
func findItem(id int) error {
return fmt.Errorf("erreur de base de données : %w", ErrNotFound)
}
func main() {
err := findItem(1)
if errors.Is(err, ErrNotFound) {
fmt.Println("Élément introuvable")
} else {
fmt.Println("Autre erreur :", err)
}
}
errors.As
Convertir l'erreur en un type spécifique pour un traitement ultérieur.
Exemple
import (
"errors"
"fmt"
)
type MyError struct {
Code int
Msg string
}
func (e *MyError) Error() string {
return fmt.Sprintf("Code: %d, Msg: %s", e.Code, e.Msg)
}
func getError() error {
return &MyError{Code: 404, Msg: "Not Found"}
}
func main() {
err := getError()
var myErr *MyError
if errors.As(err, &myErr) {
fmt.Printf("Custom error - Code: %d, Msg: %s\n", myErr.Code, myErr.Msg)
}
}
panic et recover
Le panic de Go est utilisé pour gérer les erreurs irrécupérables, et recover est utilisé pour récupérer d'un panic.
panic:
- Provoque le plantage du programme et affiche les informations de pile.
- Souvent utilisé lorsque le programme ne peut pas continuer à s'exécuter.
recover:
- catch
panicéviter les plantages du programme.
Exemple
import "fmt"
func safeFunction() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Récupéré après une panique :", r)
}
}()
panic("quelque chose s'est mal passé")
}
func main() {
fmt.Println("Démarrage du programme...")
safeFunction()
fmt.Println("Le programme a continué après la panique")
}
Exécutez le code ci-dessus, la sortie est :
Starting program... Recovered from panic: something went wrong Program continued after panicautres extensions