猿问

不一致的错误:换行 / 错误 - 展开 / fmt.Errorf(%w)

fmt.Errorf使用with%w和 using包装错误之间似乎存在不一致errors.Wrap:


    e1 := errors.New("error1")

    efmt := fmt.Errorf("error2: %w", e1)

    eerr := errors.Wrap(e1, "error2")


    fmt.Println(errors.Unwrap(efmt))       // error1

    fmt.Println(errors.Unwrap(efmt) == e1) // true

    fmt.Println(errors.Unwrap(eerr))       // error2: error1

    fmt.Println(errors.Unwrap(eerr) == e1) // false :-(

此处提供了完整示例


我不确定这是否是有意的,但这似乎不一致......有什么理由吗?这在任何地方都有记录吗?


一只萌萌小番薯
浏览 145回答 1
1回答

繁华开满天机

这是预期的工作,这不违反文档。多个错误可能包含在单个error值中,并且由于调用Unwrap()返回单个错误,显然没有得到您期望的内容并不意味着没有包含预期的错误。该errors软件包来自标准库。它没有errors.Wrap()功能。您使用的是 from github.com/pkg/errors.Wrap(),它在引擎盖下进行“双重包装”。首先它用给定的错误消息包装错误,然后再次包装以保留堆栈信息:// Wrap returns an error annotating err with a stack trace// at the point Wrap is called, and the supplied message.// If err is nil, Wrap returns nil.func Wrap(err error, message string) error {    if err == nil {        return nil    }    err = &withMessage{        cause: err,        msg:   message,    }    return &withStack{        err,        callers(),    }}当您调用时Unwrap(),将返回来自第二次包装的错误(这不是原始错误,而是包装原始错误的包装错误),Unwrap()再次调用将返回原始错误。fmt.Println("Double unwrap:",    errors.Unwrap(errors.Unwrap(err2wrp)) == err1)这就是为什么你应该使用errors.Is()来避免这种“怪癖”:fmt.Println("Proper use:", errors.Is(err2wrp, err1))在Go Playground上试试这些。请注意,以上报告true是您调用github.com/pkg/errors.Is()还是标准库的errors.Is().
随时随地看视频慕课网APP

相关分类

Go
我要回答