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
}
Vous pouvez utiliser les fonctions strings.Join()
et append()
pour obtenir cette tranche.
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!
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())
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 .
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.".
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 .
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