Go 组合多个错误字符串

Go 组合多个错误字符串,go,error-handling,Go,Error Handling,我是golang的新手,我的应用程序需要在一个循环中返回多个错误,之后需要合并并作为单个错误字符串返回。我无法使用字符串函数组合错误消息。在返回之前,可以使用哪些方法将这些错误合并为单个错误 package main import ( "fmt" "strings" ) func Servreturn() (err error) { err1 = fmt.Errorf("Something else occured") err2 = fmt.Errorf("Some

我是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

}

字符串函数不处理错误,因为error实际上是实现函数error()字符串的接口

可以在err1.Error()和err2.Error()上使用字符串函数 但不是在“err1”引用本身上

有些错误是结构化的,比如从数据库驱动程序中得到的错误

所以在错误上使用字符串函数是不自然的,因为它们下面可能不是字符串

至于合并两个错误:

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

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

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

要扩展@WillC在评论中提到的内容,可以将您自己的
error
类型定义为
error
是一种接口类型。任何实现
Error()字符串
函数的类型都实现
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()string
时,它将迭代切片并创建一个串联的错误字符串

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

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

    fmt.Println(collector)
}
func main(){
收集器:=新的(ErrorCollector)
对于i:=0;i<10;i++{
collector.Collect(errors.New(fmt.Sprintf(“%d Error”,i)))
}
fmt.Println(收集器)
}

有一个伟大的更详细的错误检查。上提供了该示例的完整示例。

您可以使用
strings.Join()
append()
函数来获取此片段

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

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

希望这有帮助

人们可能感兴趣的是,它将自己描述为“一个Go(golang)包,用于将错误列表表示为单个错误。”

使用此功能:

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...)
}
当所有错误都为零时,它会给你零;当只有一个非零错误时,它会给你相同的错误;当有多个非零错误时,它会给你非零错误的编号列表

请在此处试用:

Go 1.13的更新:

截止到,该语言现在直接支持

您可以使用
fmt.Errorf
中的
%w
动词包装错误:

err := errors.New("Original error")
err = fmt.Errorf("%w; Second error", err)
用于删除上次添加的错误,并返回剩余的内容:
previousErrors:=errors.Unwrap(err)

另外两个函数,并提供检查和检索特定类型错误的方法


Dave Cheney出色的
错误
包()包括一个
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)
时输出堆栈跟踪的选项

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

优步有一个用于此用例的软件包:

返回多错误组合(err1,err2)

这似乎对我很有效(空格分隔错误):

  • 将所有错误放在错误片/列表/数组中,即:var errors[]error
  • fmt.Sprintf(“%s”,错误)

  • 除了使用fmt.Errorf()之外,还有其他方法吗?为什么我不能使用string函数?当然可以。这取决于你所说的“结合”的真正含义。字符串连接是使用
    +
    运算符完成的。或者您可以将它们单独存储在一个切片中,
    append()。这个问题建议你自己完成一个围棋教程,并获得一本关于它的书。@GregPetr另一个可能的干净方法是拥有自己的
    CombinedError
    struct,它将错误列表作为字段,并实现
    Error()string
    方法,然后执行你想要的操作,不管是串接字符串还是其他什么。没有足够的信息。客户做什么?你的服务器做什么?示例输出。谢谢,您的示例非常有用。我会尝试一下,然后回来。@BenCampbell这里有没有理由让方法接收器成为指针?谢谢你的提示。如果有可能添加一个nil错误,error()函数应该对收集的错误执行nil检查。如果只使用索引而不使用索引+值进行访问,则需要在索引访问之前强制转换错误数组。这里有一个例子:@Rakesh No.
    func(c*ErrorCollector)Error()(err string)
    应该是
    func(c ErrorCollector)Error()(err string)
    。包装不适用于多个错误。它用于用更多上下文包装一个错误。
    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"
    }
    
        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)