Gestion des erreurs dans le langage de programmation Go

Ce chapitre vous montre comment gérer vos erreurs en GoLang, vous allez apprendre à détecter, créer et gérer vos erreurs dans le langage de programmation GO.

Présentation

Il est possible avec le langage de programmation go de gérer les erreurs plus précisément Go nous permet de détecter ou de créer une erreur pour ensuite la manier comme bon nous semble.

La première chose à réaliser pour gérer d’éventuelles erreurs lors de votre compilation, c'est avant tout de les repérer 👀.

femme qui cherche quelque chose

Détection d'erreurs

Je vais volontairement sur cet exemple provoquer une erreur lors de l'exécution d'une fonction, et le compilateur va nous prévenir d’une manière ou d’une autre qu’une erreur a été levée.

package main

import (
    "bufio"
    "fmt"
    "os"
    "strconv"
)

func division() {
    scanner := bufio.NewScanner(os.Stdin)
    fmt.Print("Entrez un chiffre : ")
    scanner.Scan()
    nbr, _ := strconv.Atoi(scanner.Text())
    fmt.Println("Résultat :", 1000/nbr)
}

func main() {
    division()
    fmt.Println("Fin")
}

Erreur :

Entrez un chiffre : nope
panic: runtime error: integer divide by zero

Sans aucune surprise nous obtenons une erreur qui nous explique qu'il est impossible de diviser par 0.

Pour le bon déroulement de notre programme, il faut gérer cette erreur en expliquant à l'utilisateur qu'il n'est pas possible de diviser par 0 et qu'il doit rentrer un nombre supérieur à 0.

package main

import (
    "bufio"
    "fmt"
    "os"
    "strconv"
)

func division() {
    for true {
        scanner := bufio.NewScanner(os.Stdin)
        fmt.Print("Entrez un chiffre : ")
        scanner.Scan()
        nbr, _ := strconv.Atoi(scanner.Text())
        if nbr <= 0 {
            fmt.Println("[division par zéro impossible] Votre valeur doit être supérieur ou égal à 0")
        } else {
            fmt.Println("Résultat :", 1000/nbr)
            break
        }
    }

}

func main() {
    division()
    fmt.Println("Fin")
}

Résultat :

Entrez un chiffre : dsfsdf
[division par zéro impossible] Votre valeur doit être supérieur ou égal à 0
Entrez un chiffre : dssd
[division par zéro impossible] Votre valeur doit être supérieur ou égal à 0
Entrez un chiffre : 78
Résultat : 12
Fin

C'est cool car on a résolu le problème de la division par zéro mais par contre lorsque l'utilisateur rentre des caractères on lui affiche toujours le même message comme quoi son entrée doit être supérieur à 0. Il serait plus judicieux de l'informer qu'il doit rentrer un nombre et non des caractères.

Pour afficher cette information on va analyser un peu plus en détail la fonction Atoi().

Déjà une chose est sûr l'erreur est levée lors de la fonction Atoi(), voyons voir un peu plus en détail le prototype de cette fonction :

func Atoi(s string) (int, error)

On peut apprendre grâce au prototype que la fonction Atoi() retourne deux types de valeurs :

  • Un type int qui correspond à la chaîne de caractères s converti en entier
  • un type error qui est l'erreur retourné par la fonction Atoi() qu'on peut gérer

Donc pour gérer cette erreur de conversion il faut vérifier la valeur de retour de error de la fonction Atoi() dans une condition.

package main

import (
    "bufio"
    "fmt"
    "os"
    "strconv"
)

func division() {
    for true {
        scanner := bufio.NewScanner(os.Stdin)
        fmt.Print("Entre un chiffre : ")
        scanner.Scan()
        nbr, err := strconv.Atoi(scanner.Text())
        if err != nil { // Gestion de l'erreur de la fonction  Atoi()
            fmt.Println("Vous devenez rentrer un nombre et non une chaîne de caractères !")
        } else if nbr <= 0 {
            fmt.Println("[division par zéro impossible] Votre valeur doit être supérieur ou égal à 0")
        } else {
            fmt.Println("Résultat :", 1000/nbr)
            break
        }
    }
}

func main() {
    division()
    fmt.Println("Fin")
}        

Résultat :

Entre un chiffre : -5
[division par zéro impossible] Votre valeur doit être supérieur ou égal à 0
Entre un chiffre : nope
Vous devenez rentrer un nombre et non une chaîne de caractères !
Entre un chiffre : 5
Résultat : 200
Fin

Créer une erreur

L'interface error

Il est possible de construire un message d'erreur grâce à la fonction New() de la structure errors.

package main

import (
    "errors"
    "fmt"
    "os"
)

func verificationDivision(nbr float64) (float64, error) {
    if nbr <= 0 {
        return 0, errors.New("Erreur: Il est impossible de diviser par 0 !") //création de l'erreur
    } else {
        return nbr, nil // on retourne nil si aucune erreur est détectée
    }
}

func main() {
    nbr := 0.0

    nbr, err := verificationDivision(nbr)

    if err != nil {
        panic(err)
    } else {
        fmt.Println("Aucune erreur")
    }
}

Résultat :

panic: Erreur: Il est impossible de diviser par 0 !

goroutine 1 [running]:
exit status 2

Information

Si votre fonction retourne une interface error alors vous ne pouvez retourner que le type nil ou le type errors

Ici j'utilise la fonction panic() pour quitter mon programme avec un code retour différent de 0. Un code d'erreur égale à zéro indique que l'exécution de votre programme s'est bien déroulée si il est différent de zéro cela indique un échec de votre programme. C'est une valeur qui est retournée lors de la fin d'exécution de votre programme.

Sur Linux il est possible d'afficher le dernier code d'erreur d'un programme/commande en utilisant la commande suivante :

echo $?

Il est intéressant de retourner le bon code d'erreur lors de l'exécution de votre programme, car c'est possible que cette valeur soit récupérée et exploitée par une autre personne qui utilise votre programme en tant que script pour vérifier si votre programme s'est bien exécuté.

Recommandation

la fonction errors.New() ne fait que renvoyer un string, donc il est totalement possible de créer votre propre système de gestion d'erreur comme sur l'exemple ci-dessous :

package main

import (
	"fmt"
)

func verificationDivision(nbr float64) (float64, bool) {
	if nbr <= 0 {
		return 0, false
	} else {
		return nbr, true
	}
}

func main() {
	nbr := 0.0

	nbr, err := verificationDivision(nbr)

	if err == false {
		panic("Erreur: Il est impossible de diviser par 0 !")
	} else {
		fmt.Println("Aucune erreur")
	}
}

Mais il reste préférable de gérer vos erreurs en utilisant la fonction errors.New() afin de rendre votre code plus lisible et clair. Cela aide à la compréhension, à la relecture, au contrôle visuel et à la maintenance de votre code.

Espace commentaire

Écrire un commentaire

Vous devez être connecté pour poster un message !

16 commentaires

30/04/19

Notre code est plus résilient

l'implémentation de vos conseils pour créer une erreur a réduit les crashs en prod

29/04/19

Les recommandations sont pratiques, pas juste théoriques

Membre
27/04/19

Nickel la présentation, on a enfin une vision claire sur la gestion des erreurs

Membre
24/04/19

Le rappel sur l'interface error est fondamental, souvent sous-estimé

22/04/19

la détection d'erreurs est devenue plus proactive chez nous, big up

19/04/19

Comment créer une erreur de manière propre est bien expliqué, utile pour nos validations

18/04/19

Vos recommandations nous ont fait gagner du temps sur l'harmonisation de nos logs d'erreurs

16/04/19

La présentation est concise, va droit au but

13/04/19

Vraiment bon article sur la gestion des erreurs

La partie sur l'interface error a clarifié un point obscur pour toute l'équipe dev

Membre
11/04/19

La détection d'erreurs est plus robuste avec vos exemples, merci

Créer une erreur n'a jamais été aussi simple, top tuto

08/04/19

Les recommandations sont gold, on les a intégrées à notre linter

06/04/19

Le passage sur l'interface error est crucial

On avait des custom errors pas très clean, maintenant c'est carré grâce à ça

04/04/19

Merci pour les tips sur la détection d'erreurs, on a pu corriger des cas limites

Membre
02/04/19

La présentation de la gestion d'erreurs est super pertinente, ça fixe les bases

31/03/19

je suis content de faire connaissance a cet article merci beaucoup 

Rejoindre la communauté

Recevoir les derniers articles gratuitement en créant un compte !

S'inscrire