合并多个错误字符串

时间:2015-11-02 04:12:53

标签: go error-handling

我是Golang的新手,我的应用程序需要在循环中返回多个错误,以后需要组合并作为单个错误字符串返回。我无法使用字符串函数来组合错误消息。在返回之前,可以使用哪些方法将这些错误组合成单个错误?

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

}

8 个答案:

答案 0 :(得分:14)

字符串函数不会处理错误,因为错误实际上是一个实现函数Error()字符串的接口。

你可以在err1.Error()和err2.Error()上使用字符串函数 但不是" err1"引用自己。

某些错误是结构,就像您从数据库驱动程序获得的那样。

因此,在错误中使用字符串函数是不自然的,因为它们实际上可能不是字符串。

至于组合两个错误:

很简单,只需再次使用fmt.Errorf。

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

可替换地:

errors.New(err1.Error() + err2.Error())

答案 1 :(得分:9)

您可以使用strings.Join()append()函数来实现此切片。

example: 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")))


}

这将输出一个字符串,您可以将其发送回客户端。

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

希望这有帮助!

答案 2 :(得分:5)

对于这种用例,Uber有一个multierr包:

return multierr.Combine(err1, err2)

答案 3 :(得分:4)

为了扩展@WillC在评论中提到的内容,可以定义自己的error类型,因为error是一种接口类型。任何实现Error() string函数的类型都会实现error接口。因此,您可以创建一个聚合错误的CollectionError并返回一个连接的错误字符串。

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
}

这提供了一个将给定error附加到切片的集合函数。在调用Error() string时,它会迭代切片并创建一个连接的错误字符串。

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

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

    fmt.Println(collector)
}

有一个很好的golang.org blog post更详细的错误。 The Go Playground上提供了该示例的完整示例。

答案 4 :(得分:2)

人们可能会对https://github.com/hashicorp/go-multierror感兴趣,它将自己描述为“用于将错误列表表示为单个错误的A Go(golang)包。”。

答案 5 :(得分:2)

Dave Cheney出色的errors软件包(https://github.com/pkg/errors)包括一个Wrap函数,用于此目的:

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"
}

这还允许其他功能,例如解包错误原因:

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"
}

以及指定fmt.Printf("%+v\n", err)时输出堆栈跟踪的选项。

您可以在他的博客上找到有关该软件包的其他信息:herehere

答案 6 :(得分:1)

这对我来说似乎很好(空格错误):

  1. 将所有错误放入错误切片/列表/数组中,即:var errors [] error
  2. fmt.Sprintf(“%s”,错误)
    var errors []error
    errors = append(errors, fmt.Errorf("error 1"))
    errors = append(errors, fmt.Errorf("error 2"))
    errors = append(errors, fmt.Errorf("and yet another error"))
    s := fmt.Sprintf("%s", errors)
    fmt.Println(s)

答案 7 :(得分:0)

使用此功能:

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...)
}

当所有错误都为零时,它会给你nil,当只有一个非零错误时会给你同样的错误,当多个非零错误时会给你编号的非零错误列表

在此处试试:https://play.golang.org/p/WttztCr-xHG