golang 1.13 errors 包 新函数介绍

2019-10-12 09:36:01 +08:00
 guonaihong

这次 errors 包算重量级更新。很有更能把以前的一些设计模式给推到。下面聊下用法。

error 装包

以前返回一个错误,想要保存 error 链,还要定义结构体保存以前的 error 信息。感兴趣看下 syscal.ECONNREFUSED 如何封装到 url.Error 的。现在只要%w 就行

err = fmt.Errorf("第二层错误信息 %w", err)

error 解包

如果是 fmt.Errorf("%w", err) 定义的错误链可以通过

e = errors.Unwrap(e) //解包错误

装包解包需要注意的地方

装包和解包错误是一一对应的,一次 Unwrap 调用,解一次 fmt.Errorf("%w", err)调用

package main

import (
    "errors"
    "fmt"
)

func main() {

    var e, first error

    first = errors.New("head")

    e = fmt.Errorf("第一层错误:%w", first)
    e = fmt.Errorf("第二层错误:%w", e)
    e = fmt.Errorf("第三层错误:%w", e)
    e = fmt.Errorf("第四层错误:%w", e)

    //解包错误
    e = errors.Unwrap(e)
    fmt.Printf("%s\n", e)

    //解包错误
    e = errors.Unwrap(e)
    fmt.Printf("%s\n", e)

    //解包错误
    e = errors.Unwrap(e)
    fmt.Printf("%s\n", e)

    //解包错误
    e = errors.Unwrap(e)
    fmt.Printf("%s\n", e)
}

/*
第三层错误:第二层错误:第一层错误:head
第二层错误:第一层错误:head
第一层错误:head
head

*/

判断错误是否相等

过去写法 ==

if err == os.ErrNotExistF {

}

现在写法 errors.Is

以前只有一个错误,现在是错误链表,要通过 errors.Is 遍历判断

b := errors.Is(err, os.ErrNotExist)
fmt.Printf("%t\n", b)

新写法根据具体类型判断 errors.As

 if _, err := os.Open("non-existing"); err != nil {
        var pathError *os.PathError
        if errors.As(err, &pathError) {
            fmt.Println("Failed at path:", pathError.Path)
        } else {
            fmt.Println(err)
        }
    }

交流学习

errors 包的一些姿势还要等长时间使用才能完全开发出来,欢迎 v 友提出想法,一起学习。

github

https://github.com/guonaihong/gout

3628 次点击
所在节点    程序员
7 条回复
zunceng
2019-10-12 09:49:51 +08:00
一直用 errors.Wrap + errors.Cause 定位错误

有了 Unwrap 能把整个错误的堆栈打出来
zunceng
2019-10-12 09:51:15 +08:00
github.com/pkg/errors 我用这个包
guonaihong
2019-10-12 13:04:07 +08:00
@zunceng pkg/errors 挺好,但是没有 Unwrap 函数,如何和标准库打通呢?
zunceng
2019-10-12 13:14:02 +08:00
就按官方的例子 用的时候 某个函数 f() 内部

_, err := ioutil.ReadAll(r)
if err != nil {
return errors.Wrap(err, "read failed")
}

调用这个 函数 f 的地方

err := f()
switch err := errors.Cause(err).(type) {
case *MyError: // 这个 type 可以是 标准库的 error type 比如 io.EOF
// handle specifically
default:
// unknown error
}


@guonaihong
guonaihong
2019-10-12 22:28:55 +08:00
@zunceng 刚刚看了 error 包的 pr 列表。pkg/errors 要和 go1.13 兼容打通。还是要实现 Unwrap 接口。
具体可看下面的详细内容。
https://github.com/pkg/errors/pull/206/files
chennqqi
2019-10-14 10:26:12 +08:00
和低版本 go 兼容是个问题,不太敢用
guonaihong
2019-10-15 12:59:10 +08:00
@chennqqi 如果用了第三方的 error 包装库才兼容问题。以前用标准库,问题不大。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/608477

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX