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

golang 1.13 errors 包来了,不用写“err 气功波”代码

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

    这篇是对 errors 包 的姿势挖掘

    气功波错误代码

    从 http.Get()返回的错误 判断 syscall.ECONNREFUSED 错误.以前要对 go 标准库 error 结构有点熟悉,才能写出下面的代码

    func CmdErr(err error) {
        if err == nil {
            return
        }   
    
        if uerr, ok := err.(*url.Error); ok {
            if noerr, ok := uerr.Err.(*net.OpError); ok {
                if scerr, ok := noerr.Err.(*os.SyscallError); ok {
                    if scerr.Err == syscall.ECONNREFUSED {
                        fmt.Printf("gurl: (7) couldn't connect to host\n")
                        return
                    }
                }
            }
        }   
    
        fmt.Printf("%s\n", err)
    }
    
    

    用 go1.13 errors 库重构气功波代码

    现在只要知道,syscall.ECONNREFUSED 就行。先用 Unwrap 不停的解包 error。最后可能得到需要的 err

    func newCmdErr(err error) {
        for {
            err = errors.Unwrap(err)
            if err == nil {
                break
            }
    
            if err == syscall.ECONNREFUSED {
                fmt.Printf("gurl: (7) couldn't connect to host\n")
                return
            }
        }
    }
    
    
    

    交流学习

    一起挖掘 errors 包的用法

    github

    https://github.com/guonaihong/gout

    第 1 条附言  ·  2019-10-14 12:25:14 +08:00

    // 这是代码量最少的写法。

    func newCmdErr2(err error) {
    
        if errors.Is(err, syscall.ECONNREFUSED) {
            fmt.Printf("gurl: (7) couldn't connect to host\n")
            return
        }   
    }
    
    20 条回复    2019-10-15 08:15:25 +08:00
    rootxigua
        1
    rootxigua  
       2019-10-14 10:11:16 +08:00
    那如果 err 不为空,并且不等于 syscall.ECONNREFUSED,这个循环会结束吗?
    edussx
        2
    edussx  
       2019-10-14 10:28:33 +08:00
    @rootxigua 这种情况下 errors.Unwrap(err)这行会一直跑,直到返回 nil,然后在下面 break 跳出循环

    具体参考这个方法的实现: https://golang.org/src/errors/wrap.go?s=372:400#L4
    lizhenda
        3
    lizhenda  
       2019-10-14 10:45:35 +08:00
    看起来写法不错,更易读了
    rootxigua
        4
    rootxigua  
       2019-10-14 11:35:04 +08:00
    @edussx 懂了。源码很清晰,谢谢
    reus
        5
    reus  
       2019-10-14 11:38:45 +08:00   ❤️ 3
    难道不是 errors.Is(err, syscall.ECONNREFUSED) 就行了?
    iugo
        6
    iugo  
       2019-10-14 11:43:19 +08:00
    还是觉得 Go 的错误处理是个值得商榷的点.
    Hanggi
        7
    Hanggi  
       2019-10-14 12:07:38 +08:00
    这个代码本来就不用写什么气功波吧?有谁会这么写吗?
    guonaihong
        8
    guonaihong  
    OP
       2019-10-14 12:23:42 +08:00
    @reus 是的,这是最优解。
    boyhailong
        9
    boyhailong  
       2019-10-14 12:26:48 +08:00
    气功波? 返回值不想处理可以忽略的
    guonaihong
        10
    guonaihong  
    OP
       2019-10-14 12:28:45 +08:00
    @boyhailong 这里的用法是,如果是 syscall.ECONNREFUSED 的错误打印 提示信息。所以就不能忽略。。。
    guonaihong
        11
    guonaihong  
    OP
       2019-10-14 12:38:30 +08:00
    @iugo 是的,现在比较大的痛点有

    ``` go
    fd, err := os.Open("文件")
    if err != nil {
    return err
    }
    ```
    如果 go 里面有语法糖,在语句结尾加个符号,生成 if err != nil { return err}的代码就好了。比如下面的伪代码.
    fd, err := os.Open("文件“) ?
    ChristopherWu
        12
    ChristopherWu  
       2019-10-14 17:12:52 +08:00
    实不相瞒,我看不懂这代码在搞啥子
    ```
    func CmdErr(err error) {
    if err == nil {
    return
    }

    if uerr, ok := err.(*url.Error); ok {
    if noerr, ok := uerr.Err.(*net.OpError); ok {
    if scerr, ok := noerr.Err.(*os.SyscallError); ok {
    if scerr.Err == syscall.ECONNREFUSED {
    fmt.Printf("gurl: (7) couldn't connect to host\n")
    return
    }
    }
    }
    }

    fmt.Printf("%s\n", err)
    }
    ```
    guonaihong
        13
    guonaihong  
    OP
       2019-10-14 18:00:35 +08:00
    @ChristopherWu 查询 err 看是否包含 syscall.ECONNREFUSED 这种情况。go1.13 以前只能这么干。。
    Nitroethane
        14
    Nitroethane  
       2019-10-14 18:30:31 +08:00 via Android
    @guonaihong 这不就是 rust 中的语法么...
    guonaihong
        15
    guonaihong  
    OP
       2019-10-14 18:50:03 +08:00
    @Nitroethane 对的,伪代码符号参考的 rust ?号,go 现在没有,有就好了。
    EscYezi
        16
    EscYezi  
       2019-10-14 21:06:36 +08:00 via iPhone
    不停的 unwrap 怎么看起来像在手动完成 java 的 printStackTrace......
    guonaihong
        17
    guonaihong  
    OP
       2019-10-14 21:20:47 +08:00
    @EscYezi 没玩过 java。。。
    mason961125
        18
    mason961125  
       2019-10-14 21:25:01 +08:00
    这样写,我觉得 https://github.com/hashicorp/errwrap 更好
    guonaihong
        19
    guonaihong  
    OP
       2019-10-14 21:52:51 +08:00
    @mason961125 谢了,我明天玩下。
    zjh6
        20
    zjh6  
       2019-10-15 08:15:25 +08:00
    气功波,是搞笑.
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2964 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 41ms · UTC 12:47 · PVG 20:47 · LAX 04:47 · JFK 07:47
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.