V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
guonaihong
V2EX  ›  程序员

golang 1.13 errors 包 新函数介绍

  •  1
     
  •   guonaihong ·
    guonaihong · 2019-10-12 09:36:01 +08:00 · 3731 次点击
    这是一个创建于 1873 天前的主题,其中的信息可能已经有所发展或是发生改变。

    这次 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

    7 条回复    2019-10-15 12:59:10 +08:00
    zunceng
        1
    zunceng  
       2019-10-12 09:49:51 +08:00
    一直用 errors.Wrap + errors.Cause 定位错误

    有了 Unwrap 能把整个错误的堆栈打出来
    zunceng
        2
    zunceng  
       2019-10-12 09:51:15 +08:00
    github.com/pkg/errors 我用这个包
    guonaihong
        3
    guonaihong  
    OP
       2019-10-12 13:04:07 +08:00
    @zunceng pkg/errors 挺好,但是没有 Unwrap 函数,如何和标准库打通呢?
    zunceng
        4
    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
        5
    guonaihong  
    OP
       2019-10-12 22:28:55 +08:00   ❤️ 1
    @zunceng 刚刚看了 error 包的 pr 列表。pkg/errors 要和 go1.13 兼容打通。还是要实现 Unwrap 接口。
    具体可看下面的详细内容。
    https://github.com/pkg/errors/pull/206/files
    chennqqi
        6
    chennqqi  
       2019-10-14 10:26:12 +08:00
    和低版本 go 兼容是个问题,不太敢用
    guonaihong
        7
    guonaihong  
    OP
       2019-10-15 12:59:10 +08:00
    @chennqqi 如果用了第三方的 error 包装库才兼容问题。以前用标准库,问题不大。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4884 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 10:00 · PVG 18:00 · LAX 02:00 · JFK 05:00
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.