V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
d0m2o08
V2EX  ›  Go 编程语言

请教一下怎么优雅的处理 go 中的 err

  •  
  •   d0m2o08 · 2019-05-24 08:51:41 +08:00 · 9850 次点击
    这是一个创建于 2016 天前的主题,其中的信息可能已经有所发展或是发生改变。
    go 中大部分短赋值都会有一个 xx, err :=
    难道要每次都 if err != nil 么
    大佬都是用什么方式处理的?

    func checkErr(err error) {
    if err != nil{
    panic(err)
    }
    }

    这样貌似也很低级啊
    62 条回复    2022-08-08 19:21:15 +08:00
    guonaihong
        1
    guonaihong  
       2019-05-24 08:56:12 +08:00
    不用 hack 第三库只能这样,或者等 go2.0
    Fule
        2
    Fule  
       2019-05-24 09:07:33 +08:00   ❤️ 3
    很久以前研究 GO 的时候,仿佛还说这种 if err != nil 的方式是优点,参数类型放在后面也是优点 …… 我几乎相信了……
    wangsongyan
        3
    wangsongyan  
       2019-05-24 09:10:49 +08:00
    反正我是写 if err != nil return 写吐了
    lhx2008
        4
    lhx2008  
       2019-05-24 09:11:36 +08:00
    这个是真的不方便,try catch finally 被 Go 搞成 err != nil, recover, defer
    araraloren
        5
    araraloren  
       2019-05-24 09:11:48 +08:00
    多返回值的滥用。。
    Muninn
        6
    Muninn  
       2019-05-24 09:27:19 +08:00
    在 vscode 里打 ife 然后自动补全……
    因为 golang 里概率最大的是返回一个 struct 的指针加 err,所以自动补全的这个也是返回 nil,err
    如果只有一个返回值 err,再按 tab 把 nil 删掉就好了。
    其实也就看起来浪费行数,用起来还是不错的,各种地方都无脑返回,只在最高层统一处理就好了。

    API 的话可以在框架集中处理,参考我这篇文章
    https://zhuanlan.zhihu.com/p/26300634
    dodo2012
        7
    dodo2012  
       2019-05-24 09:28:16 +08:00
    if err != nil 是真的太啰嗦,
    Qzier
        8
    Qzier  
       2019-05-24 09:32:24 +08:00
    这是所谓的“特性”,无解。
    HuasLeung
        9
    HuasLeung  
       2019-05-24 09:32:24 +08:00
    关键是这种写法
    ````
    if err:= xxx; err != nil {
    //
    }
    ````
    刚开始写 go 的时候很不习惯,跟 for 神似……
    HuasLeung
        10
    HuasLeung  
       2019-05-24 09:33:09 +08:00
    @HuasLeung err := xxx 空格打多了
    freestyle
        11
    freestyle  
       2019-05-24 09:36:39 +08:00 via iPhone
    https://imhanjm.com/2018/07/08/go 代码如何优雅地错误处理(error%20handling%20and%20go%201)/
    pmispig
        13
    pmispig  
       2019-05-24 09:43:16 +08:00   ❤️ 1
    我现在已经接受了这种写法了,反过来想,C 不是也得判断返回值是否大于 0 吗
    zvall
        14
    zvall  
       2019-05-24 09:44:59 +08:00
    趁早放弃 go 吧
    chenset
        15
    chenset  
       2019-05-24 09:49:29 +08:00
    Live Templates 缓解一下
    zzn
        16
    zzn  
       2019-05-24 09:54:26 +08:00
    错误处理本来就是个大难题, 异常也不见得有好多多少

    但是在 go 里面逢错误就 panic 的写法毫无疑问很低级
    VDimos
        17
    VDimos  
       2019-05-24 09:59:43 +08:00 via Android
    和 rust 的 Result 有得一拼
    Vegetable
        18
    Vegetable  
       2019-05-24 09:59:54 +08:00
    这个让我想起了地铁的手指口呼.

    https://zh.wikipedia.org/wiki/%E6%8C%87%E5%B7%AE%E7%A2%BA%E8%AA%8D

    这样强迫 coder 显式处理每一个可能出现的错误,可以说是有好处的,可以说现在写输入 ife 已经成了肌肉记忆了 233333
    chenset
        19
    chenset  
       2019-05-24 10:06:08 +08:00
    看了下 Go 2 引入了 check & handle https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling-overview.md#draft-design

    ```

    func CopyFile(src, dst string) error {
    handle err {
    return fmt.Errorf("copy %s %s: %v", src, dst, err)
    }

    r := check os.Open(src)
    defer r.Close()

    w := check os.Create(dst)
    handle err {
    w.Close()
    os.Remove(dst) // (only if a check fails)
    }

    check io.Copy(w, r)
    check w.Close()
    return nil
    }

    ```
    cubecube
        20
    cubecube  
       2019-05-24 10:10:19 +08:00 via Android
    异常可以不处理,一直抛啊。
    keysona
        21
    keysona  
       2019-05-24 10:20:04 +08:00   ❤️ 1
    习惯就好。

    c 的返回也是这样写的。

    一开始我写 java 的 try catch 也写吐了。

    每个语言都有罗嗦烦人的地方。大部分情况只能你去适应了,不想适应就换语言吧。
    keepeye
        22
    keepeye  
       2019-05-24 10:22:39 +08:00
    虽然写的很不爽,但不能否认,这样写出来的程序是比脚本语言写出来的更健壮一些。另外 try ... catch 也不见得有多好
    dabaibai
        23
    dabaibai  
       2019-05-24 10:35:50 +08:00
    这种比 try catch 要好,
    写过 10 年 C++的 是这么认为的
    SurfaceView
        24
    SurfaceView  
       2019-05-24 10:36:29 +08:00
    @Fule 完全同意,这 2 个点完全是 xxx 的存在,那个 err 我先不评价什么,毕竟是特性, 但是那个类型放后面
    纯粹是为了跟别人不一样 而不一样。
    impl
        25
    impl  
       2019-05-24 10:37:41 +08:00 via Android
    用上 rust,只想说没有 nil 和 null 的世界真美好。回去看以前写的 go 代码,一堆 nil 堆的像屎山一样。。
    pmispig
        26
    pmispig  
       2019-05-24 10:42:21 +08:00
    @impl 老哥,rust 这么丑陋的语法和一堆符号是怎么克服的,我试了好多次想学,看着看着就想吐了。。
    Kilerd
        27
    Kilerd  
       2019-05-24 10:46:35 +08:00
    @pmispig #26 不是我吐槽你,Rust 除了显式生命周期难看一点以外,其他都比 Go 好多了好吗? 而且现在有 Miri 和 NLL 的支持,很少机会能写到显式生命周期了(除非写底层)
    ZSeptember
        28
    ZSeptember  
       2019-05-24 10:47:00 +08:00
    跟异常一样,往上抛,调用方处理。
    当然,如果是不能处理的错误,直接 panic 也没问题。
    pmispig
        29
    pmispig  
       2019-05-24 10:50:18 +08:00
    @Kilerd 主要是各种符号太多了,看得我脑壳晕
    gamexg
        30
    gamexg  
       2019-05-24 10:50:27 +08:00
    用 golang,打 err 自动补全 if,还算可以接受
    Kilerd
        31
    Kilerd  
       2019-05-24 10:56:17 +08:00
    @pmispig #29 可能我写习惯了,没发现有什么太多的符号(连 JS 的一半都没有呢)

    || 表示闭包
    ! 表示 宏
    ? 向上抛异常。

    也就这几个比较特殊的
    pmispig
        32
    pmispig  
       2019-05-24 11:06:22 +08:00
    @Kilerd
    ```
    client.get(uri).and_then(|res| {
    println!("Response: {}", res.status());

    res.body().for_each(|chunk| {
    io::stdout()
    .write_all(&chunk)
    .map_err(From::from)
    })
    });
    ```
    有种一口气走到底的感觉,有点喘不过气。像以前 js express 那种回调层层嵌套,全是匿名函数的错觉...
    beidounanxizi
        33
    beidounanxizi  
       2019-05-24 11:09:28 +08:00
    看看 gopheracdamey 写的系列文章 楼主问的问题 go github wiki 有很多好资料 仔细找找不难发现
    impl
        34
    impl  
       2019-05-24 11:27:54 +08:00 via Android
    @pmispig 把 book 看一遍,掌握 struct,enum,match,if let 这些东西先,觉得有意思了再继续深入
    impl
        35
    impl  
       2019-05-24 11:34:08 +08:00 via Android
    @pmispig 已经开始支持 async/await,后面不用 and_then 这种写法。romio 了解一下
    ICKelin
        36
    ICKelin  
       2019-05-24 11:36:16 +08:00
    我觉得 go 的错误处理写法没啥问题,但是通常我写 go 是基本不会写 panic 和 recover 的。。
    Hellert
        37
    Hellert  
       2019-05-24 11:45:44 +08:00
    Go 的错误处理除了啰嗦点,其实没什么大毛病,这点就是继承了 C 语言程序就是输入+输入出的设计,简单。try catch 这种也不是万能的。
    错误处理 Go2 做了优化,应该会少写一些 if。

    其实能和 Go 语言做比较的只有 C,拿其它语言和 Go 比都不是太恰当,比如指针这个概念,大多数现代语言都放弃了,但在 Go 中却是非常核心的东西。
    还有面向对象的那一堆理论,Go 完全没有,怎么去和 Java 这种比较?
    knowckx
        38
    knowckx  
       2019-05-24 12:04:12 +08:00
    通过编辑器的 snippets 来自动完成有关错误处理的代码,工作效率会高很多

    if err != nil {
    log.Err("%s", err)
    }
    impl
        39
    impl  
       2019-05-24 12:19:02 +08:00 via Android
    rob 想保持 go 简单和地道,现在关于 go 那些改进的方案,rob 说了,可能都不会合到 go2 里面。油管视频
    其实 go 这门语言多年前就死了。go2 可能就是画出来的大饼,什么时候能出来,没人知道。
    loading
        40
    loading  
       2019-05-24 12:35:50 +08:00 via Android
    我也有一个 FuckErr()
    zeromake
        41
    zeromake  
       2019-05-24 13:28:39 +08:00 via Android
    这些返回错误搞得栈信息全丢了
    liuxey
        42
    liuxey  
       2019-05-24 14:07:35 +08:00
    既然选择了 Go,那么就用 Go 的方式处理错误,Go 不是一门语法“优雅”的语言
    Nugine0
        43
    Nugine0  
       2019-05-24 14:12:01 +08:00 via Android
    @pmispig 问号操作符能缓解,等 async/await 稳定后写异步也能喘气了
    ysc3839
        44
    ysc3839  
       2019-05-24 14:13:45 +08:00 via Android
    @pmispig 但是 C 有 #define,可以弄成 CHECK_RETURN(function());
    index90
        45
    index90  
       2019-05-24 14:38:21 +08:00
    都说 if err != nil 不好,我想问,你们认为好的是怎样的?
    RubyJack
        46
    RubyJack  
       2019-05-24 15:17:48 +08:00
    我从 if err != nil 中学到了很多,原来这个底层调用也可能报错
    WilliamYang
        47
    WilliamYang  
       2019-05-24 15:39:40 +08:00
    我已经习惯,并可能喜欢上它了
    Skye347
        48
    Skye347  
       2019-05-24 15:40:05 +08:00 via Android   ❤️ 2
    就 Rust 而言,只有错误没有异常,可能出错的地方统一用 Result<Item,Error>代替,不想处理直接往上抛直接打?号,不想处理显示报错直接.unwrap (),不想处理直接忽略有 if let,不想处理带默认值有 unwrap_or(),想处理直接用 match 处理部分或全部情况,再或者结合 map 等函数式风格随意组合,多种方式随意选择,还有 IDE/编译器提示。
    不过 go 选择了类 c 的风格,强调简单,那也没哪个好或者不好的了。
    neoblackcap
        49
    neoblackcap  
       2019-05-24 16:03:29 +08:00   ❤️ 4
    @Skye347 就 Result 这个设计就是吸收了多年 PL 研究成果的好东西,配合自带的各种方法,写起代码行云流水。错误能处理的就处理,不能处理就抛给 caller,还能配合编译器进行类型检查,Monad 的应用,这么好的东西有人理解不了,硬说跟 error code 一样,还能说什么。我觉得这些人用 Go 跟 C 都挺好的,记得不要忘记检查错误码就好了
    skadi
        50
    skadi  
       2019-05-24 19:11:50 +08:00 via iPhone
    defer
    sunny352787
        51
    sunny352787  
       2019-05-24 19:23:58 +08:00
    你们这帮 Java 转 Go 的肯定都喜欢 try,就是习惯
    你看像我们 C++转 Go 的从来不会提这类问题~
    svenFeng
        52
    svenFeng  
       2019-05-24 20:00:47 +08:00 via Android
    这都能讨论这么多,我的天,不就是个 Monad 随手就能解决的问题么,真是尴尬
    petelin
        53
    petelin  
       2019-05-24 20:33:15 +08:00 via iPhone
    你们这些都不看错误怎么处理的人 能写出什么严谨的程序
    zhuangzhuang1988
        54
    zhuangzhuang1988  
       2019-05-24 20:37:49 +08:00
    换个语言
    derek80
        55
    derek80  
       2019-05-24 20:44:29 +08:00 via iPhone
    @SurfaceView pascal 也是放后面啊,还有 var
    Tyanboot
        56
    Tyanboot  
       2019-05-25 01:08:07 +08:00 via Android
    @VDimos Rust 的 Result 和 Option 不知道比 go 的 err 高到哪里去了🙃。
    python
        57
    python  
       2019-05-25 10:51:11 +08:00 via Android
    习惯成自然
    skiy
        58
    skiy  
       2019-05-25 11:14:58 +08:00
    slice[0:100]
    当 100 超出了 len(slice),就报错了,特别烦这个,有解决方案么
    neoblackcap
        59
    neoblackcap  
       2019-05-25 12:57:48 +08:00
    @skiy 你为什么需要访问越界的元素?
    Karblue
        60
    Karblue  
       2019-05-25 13:19:37 +08:00
    吐槽 err 的几乎是喜欢把所有都错误 try catch 的人,虽然确实很啰嗦,但是这个特性写过 c/c++的人就知道,还是比较方便的.
    更严谨,也更啰嗦,至少更能了解程序内部哪个地方出错了
    guanhui07
        61
    guanhui07  
       2019-07-05 09:39:56 +08:00
    挺好的 期待 2.0
    gaifanking
        62
    gaifanking  
       2022-08-08 19:21:15 +08:00
    @Karblue java try catch 有堆栈信息啊,一样能看到哪行错了,把所有代码整个 try catch 完事。go 每一个调用都要写。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1204 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 23:52 · PVG 07:52 · LAX 15:52 · JFK 18:52
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.