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

2019-10-14 09:34:13 +08:00
 guonaihong

这篇是对 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

5405 次点击
所在节点    程序员
20 条回复
rootxigua
2019-10-14 10:11:16 +08:00
那如果 err 不为空,并且不等于 syscall.ECONNREFUSED,这个循环会结束吗?
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
2019-10-14 10:45:35 +08:00
看起来写法不错,更易读了
rootxigua
2019-10-14 11:35:04 +08:00
@edussx 懂了。源码很清晰,谢谢
reus
2019-10-14 11:38:45 +08:00
难道不是 errors.Is(err, syscall.ECONNREFUSED) 就行了?
iugo
2019-10-14 11:43:19 +08:00
还是觉得 Go 的错误处理是个值得商榷的点.
Hanggi
2019-10-14 12:07:38 +08:00
这个代码本来就不用写什么气功波吧?有谁会这么写吗?
guonaihong
2019-10-14 12:23:42 +08:00
@reus 是的,这是最优解。
boyhailong
2019-10-14 12:26:48 +08:00
气功波? 返回值不想处理可以忽略的
guonaihong
2019-10-14 12:28:45 +08:00
@boyhailong 这里的用法是,如果是 syscall.ECONNREFUSED 的错误打印 提示信息。所以就不能忽略。。。
guonaihong
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
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
2019-10-14 18:00:35 +08:00
@ChristopherWu 查询 err 看是否包含 syscall.ECONNREFUSED 这种情况。go1.13 以前只能这么干。。
Nitroethane
2019-10-14 18:30:31 +08:00
@guonaihong 这不就是 rust 中的语法么...
guonaihong
2019-10-14 18:50:03 +08:00
@Nitroethane 对的,伪代码符号参考的 rust ?号,go 现在没有,有就好了。
EscYezi
2019-10-14 21:06:36 +08:00
不停的 unwrap 怎么看起来像在手动完成 java 的 printStackTrace......
guonaihong
2019-10-14 21:20:47 +08:00
@EscYezi 没玩过 java。。。
mason961125
2019-10-14 21:25:01 +08:00
这样写,我觉得 https://github.com/hashicorp/errwrap 更好
guonaihong
2019-10-14 21:52:51 +08:00
@mason961125 谢了,我明天玩下。
zjh6
2019-10-15 08:15:25 +08:00
气功波,是搞笑.

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

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

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

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

© 2021 V2EX