V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
guonaihong
V2EX  ›  程序员

golang 1.13 errors 包 新函数介绍

  •  1
     
  •   guonaihong ·
    guonaihong · Oct 12, 2019 · 4091 views
    This topic created in 2403 days ago, the information mentioned may be changed or developed.

    这次 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 replies    2019-10-15 12:59:10 +08:00
    zunceng
        1
    zunceng  
       Oct 12, 2019
    一直用 errors.Wrap + errors.Cause 定位错误

    有了 Unwrap 能把整个错误的堆栈打出来
    zunceng
        2
    zunceng  
       Oct 12, 2019
    github.com/pkg/errors 我用这个包
    guonaihong
        3
    guonaihong  
    OP
       Oct 12, 2019
    @zunceng pkg/errors 挺好,但是没有 Unwrap 函数,如何和标准库打通呢?
    zunceng
        4
    zunceng  
       Oct 12, 2019
    就按官方的例子 用的时候 某个函数 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
       Oct 12, 2019   ❤️ 1
    @zunceng 刚刚看了 error 包的 pr 列表。pkg/errors 要和 go1.13 兼容打通。还是要实现 Unwrap 接口。
    具体可看下面的详细内容。
    https://github.com/pkg/errors/pull/206/files
    chennqqi
        6
    chennqqi  
       Oct 14, 2019
    和低版本 go 兼容是个问题,不太敢用
    guonaihong
        7
    guonaihong  
    OP
       Oct 15, 2019
    @chennqqi 如果用了第三方的 error 包装库才兼容问题。以前用标准库,问题不大。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   5976 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 52ms · UTC 03:41 · PVG 11:41 · LAX 20:41 · JFK 23:41
    ♥ Do have faith in what you're doing.