web-dev-qa-db-fra.com

Combinez plusieurs chaînes d'erreur

Je suis nouveau sur golang, mon application doit renvoyer plusieurs erreurs dans une boucle, elle doit ensuite être combinée et renvoyée sous forme de chaîne d'erreur unique. Je ne suis pas en mesure d'utiliser les fonctions de chaîne pour combiner les messages d'erreur. Quelles méthodes peuvent être utilisées pour combiner ces erreurs en une seule erreur avant de retourner? 

package main

import (
   "fmt"
   "strings"
)

func Servreturn() (err error) {

   err1 = fmt.Errorf("Something else occured")
   err2 = fmt.Errorf("Something else occured again")

   // concatenate both the error

   return err3

}
11
Greg Petr

Vous pouvez utiliser les fonctions strings.Join() et append() pour obtenir cette tranche. 

exemple: golang playgorund

package main

import (
    "fmt"
    "strings"
    "syscall"
)

func main() {

    // create a slice for the errors
    var errstrings []string 

    // first error
    err1 := fmt.Errorf("First error:server error")
    errstrings = append(errstrings, err1.Error())

    // do something 
    err2 := fmt.Errorf("Second error:%s", syscall.ENOPKG.Error())
    errstrings = append(errstrings, err2.Error())

    // do something else
    err3 := fmt.Errorf("Third error:%s", syscall.ENOTCONN.Error())
    errstrings = append(errstrings, err3.Error())

    // combine and print all the error
    fmt.Println(fmt.Errorf(strings.Join(errstrings, "\n")))


}

Cela produirait une seule chaîne que vous pouvez renvoyer au client.

First error:server1 
Second error:Package not installed 
Third error:Socket is not connected

j'espère que cela t'aides!

9
askb

Les fonctions de chaîne ne fonctionnent pas sur les erreurs, car error est en réalité une interface qui implémente la fonction Error ().

Vous pouvez utiliser des fonctions de chaîne sur err1.Error () et err2.Error () Mais pas sur la référence "err1" elle-même.

Certaines erreurs sont des structures, comme celles que vous obtenez des pilotes de base de données.

Il n’existe donc aucun moyen naturel d’utiliser des fonctions de chaîne sur les erreurs car il se peut qu’elles ne soient pas réellement des chaînes en dessous.

Quant à la combinaison de deux erreurs:

Facile, utilisez à nouveau fmt.Errorf.

fmt.Errorf("Combined error: %v %v", err1, err2)

Alternativement:

errors.New(err1.Error() + err2.Error())
12
David Budworth

Pour développer ce que @WillC a mentionné dans un commentaire, il est possible de définir votre propre type error car error est un type d'interface. Tout type qui implémente une fonction Error() string implémente l'interface error. Par conséquent, vous pouvez créer une variable CollectionError qui regroupe les erreurs et renvoie une chaîne d'erreur concaténée. 

type ErrorCollector []error

func (c *ErrorCollector) Collect(e error) { *c = append(*c, e) }

func (c *ErrorCollector) Error() (err string) {
    err = "Collected errors:\n"
    for i, e := range *c {
        err += fmt.Sprintf("\tError %d: %s\n", i, e.Error())
    }

    return err
}

Ceci fournit une fonction de collection qui ajoute une error donnée à une tranche. Lors de l'appel de Error() string, il effectue une itération sur la tranche et crée une chaîne d'erreur concaténée.

func main() {
    collector := new(ErrorCollector)

    for i := 0; i < 10; i++ {
         collector.Collect(errors.New(fmt.Sprintf("%d Error", i)))
    }

    fmt.Println(collector)
}

Il existe un excellent article sur le blog -golang.org qui traite des erreurs plus en détail. Un exemple complet de cet exemple est disponible sur The Go Playground .

4
Ben Campbell

Les gens peuvent être intéressés par https://github.com/hashicorp/go-multierror qui se décrit comme "un paquet Go (golang) permettant de représenter une liste d’erreurs comme une seule erreur.".

2
Mark Lawrence

L’excellent package errors de Dave Cheney ( https://github.com/pkg/errors ) inclut une fonction Wrap à cette fin:

package main

import "fmt"
import "github.com/pkg/errors"

func main() {
        err := errors.New("error")
        err = errors.Wrap(err, "open failed")
        err = errors.Wrap(err, "read config failed")

        fmt.Println(err) // "read config failed: open failed: error"
}

Cela permet également des fonctionnalités supplémentaires, telles que la décompression de la cause de l'erreur:

package main

import "fmt"
import "github.com/pkg/errors"

func main() {
    err := errors.New("original error")
    err = errors.Wrap(err, "now this")

    fmt.Println(errors.Cause(err)) // "original error"
}

Ainsi que l'option permettant de générer une trace de pile lorsque vous spécifiez fmt.Printf("%+v\n", err).

Vous pouvez trouver des informations supplémentaires sur le paquet sur son blog: ici et ici .

1
Feckmore

Utilisez cette fonction:

func JoinErrs(errs ...error) error {
    var joinErrsR func(string, int, ...error) error
    joinErrsR = func(soFar string, count int, errs ...error) error {
        if len(errs) == 0 {
            if count == 0 {
                return nil
            }
            return fmt.Errorf(soFar)
        }
        current := errs[0]
        next := errs[1:]
        if current == nil {
            return joinErrsR(soFar, count, next...)
        }
        count++
        if count == 1 {
            return joinErrsR(fmt.Sprintf("%s", current), count, next...)
        } else if count == 2 {
            return joinErrsR(fmt.Sprintf("1: %s\n2: %s", soFar, current), count, next...)
        }
        return joinErrsR(fmt.Sprintf("%s\n%d: %s", soFar, count, current), count, next...)
    }
    return joinErrsR("", 0, errs...)
}

Cela vous donnera nil quand toutes les erreurs sont nuls, vous aurez la même erreur quand une seule erreur non-nil, vous donnera une liste numérotée d'erreurs non-nil lorsque plusieurs erreurs non-nil

Essayez-le ici: https://play.golang.org/p/WttztCr-xHG

0
Sean F