The Go Programming Language
› http://golang.org/
› Go Playground
Go Projects
› Revel Web Framework
zzhirong

探讨一下错误处理策略, 关于 if err != nil {

  •  
  •   zzhirong · Apr 28, 2025 · 3752 views
    This topic created in 553 days ago, the information mentioned may be changed or developed.

    起因是看到 https://v2ex.com/t/1128449?p=1#reply41 写了

    "相比之下 if err != nil 95%的时候都很不优雅"

    好像我也看到很多吐槽 Go 错误处理语法的, 以下错误处理策略摘录自<<The Go Programming Language>> :

    1. Propagate the error. # 上抛
    2. Retry the failed operation. # 重试
    3. If progress is impossible, the caller can print the error and stop the program gracefully. # 严重错误, 退出程序
    4. It’s sufficient just to log the error and then continue, perhaps with reduced functionality. # 打印错误, 服务降级运行
    5. In rare cases we can safely ignore an error entirely. # 忽略错误

    有无更优雅的方式能够实现上面的处理策略?

    已知的两种:

    1. try except finally 除了实现 1 (上抛)优雅点, 剩下的也没看出多大优势,而且错误发生点和处理点不在同一处,这就注定需要额外的代码来重构上下文, 比如,打开 file1, 然后 file2, 但在打开第 file2 时发生错误,处理的时候得先判定是打开哪个文件出错了,再执行相应错误处理和回滚操作。
    2. 还有 Optional 一类的,和 if 没太大区别,只不过前者在语法上做了强制(不检查错误,不能拿到结果),还有一些语法糖( user?.address)。
    Supplement 1  ·  Apr 28, 2025
    可能有点幸存者偏差缘故(在 Go 区讨论 Go 语法), 一圈看下来, 好像对 Go 错误处理都还满意, 我看下来的结论就是, 显式错误处理喜欢的人也很多, 但, 一些高频用法(简单上抛错误)还是显啰嗦, 如果是处理稍复杂点的错误逻辑的话, `if err `方式还是挺好的。

    就不占用大家时间了, 帖子下沉了。
    Ayanokouji
    Ayanokouji
    Apr 28, 2025
    1
    我之前发的帖子,有不少评论的解决方案可以参考。
    /t/1101542
    PTLin
    PTLin
    Apr 28, 2025❤️2
    2
    你先把这一百多个被毙了的提案看一下吧,可以说 99%的人能想到的方法里面都有。
    https://github.com/golang/go/issues?q=label:error-handling
    zzhirong
    zzhirong
    OP
    Apr 28, 2025
    3
    @PTLin 其实我也没感觉 if err != nil { 有太大问题, 只不过语法上确实看起来有点冗余了点。
    Subilan
    Subilan
    Apr 28, 2025 via iPhone
    5
    我觉得最难顶的还是频繁多次错误处理的场景,err 变量不能重定义,要么事先专门声明一个,要么专门为每一个错误单独起个名字来定义。有更好的办法吗?
    vczyh
    vczyh
    Apr 28, 2025
    6
    就用 err.nn 吧,别的越用越麻烦,实在不行就换语言吧
    Subilan
    Subilan
    Apr 28, 2025 via iPhone
    8
    @vczyh 确实是一个方法,但是 if 可能会堆特别长,如果这个函数有其他数据返回,剩下的操作也只能在 if 里面做😐😐😐
    zzhirong
    zzhirong
    OP
    Apr 28, 2025
    9
    @pike0002 哈哈, 算个极端例子吧, 处理上抛这种情况确实不优雅了点。
    vczyh
    vczyh
    Apr 28, 2025
    10
    @Subilan 我一般这么写: https://imgur.com/a/x4qtu9A
    aloxaf
    aloxaf
    Apr 28, 2025❤️1
    11
    > 还有 Optional 一类的,和 if 没太大区别,只不过前者在语法上做了强制(不检查错误,不能拿到结果),还有一些语法糖( user?.address)。

    大部分人想要的不就是糖吗?谁会关心和类型和积类型的区别,自己写得爽就行了。
    即使 Optional 这类方案,没有糖也很难受,比 if err != nil 好看不到哪儿去。

    比如 Rust 没有任何糖的上抛:
    let ret = match foo() {
    Ok(v) => v,
    err => return err,
    }

    后面大家受不了,加入了 try! 宏:
    let ret = try!(foo());

    再后面直接加入了问号运算符:
    let ret = foo()?;
    lesismal
    lesismal
    Apr 28, 2025
    12
    讲究工程性的工程师多数会觉得 if err 很好。
    我自己就是这种支持 if err 的,从没因为在 go 里写多几个 if err 感到任何不适,反而觉得这种强制或习惯让代码更健壮了、甚是欣慰。

    引用一段别人文章里总结的 Rob Pike 老爷子内容:
    显式错误处理:if err != nil 的模式强制开发者在调用点处理错误,使得问题更难被“隐藏”到上层去统一“包装”处理,鼓励在错误发生的源头附近解决或添加上下文。

    完整文章:
    https://tonybai.com/2025/04/27/rob-pike-on-bloat/
    zzhirong
    zzhirong
    OP
    Apr 28, 2025
    13
    @lesismal 我也认为显式比隐式更好, 目前吐槽最多的应该是, 显式上抛以及层层上抛(导致了很多重复的代码), 在翻看 #2 给出的链接中的提案时, 发现一句话, "The goal is not to replace all error handling. The goal is to replace the most common case", 我也很认可, 针对高频的用法做些优化, 也未尝不可。
    log4j
    log4j
    Apr 28, 2025
    14
    习惯了表示还行,显示处理 error 工程上来讲还是很好的
    Subilan
    Subilan
    Apr 28, 2025 via iPhone
    15
    @vczyh #10 我得感谢 Go 没有禁止这种情况下的 err 重定义(但会被 IDE 画上线)
    zzhirong
    zzhirong
    OP
    Apr 28, 2025
    16
    @log4j 确实, 对代码阅读也很友好, 相对于, 一个小小的 ? 就可能是一个函数出口来说, 好多了。
    Hopetree
    Hopetree
    Apr 28, 2025
    17
    我现在写 Python 还经常借鉴 Go 的这种显示的异常语法,Go 又不是强制让你这么写,你要是不想判断你就直接异常不就行了
    henix
    henix
    Apr 28, 2025
    18
    我比较喜欢 Go 这种错误处理方式,它的问题在于代码啰嗦,而且没有宏,而且按照 Go 语言的设计哲学,基本上不可能加入宏的
    我自己的 C 语言基础库的错误处理就参考了 Go ,而且通过宏来减少重复代码,例如:

    #define E(s) { err_t err = s; if (err != NULL) return err; } (void)0

    使用:

    E(do_some_thing(a));
    bruce0
    bruce0
    Apr 28, 2025
    19
    go 通过返回值判断错误的方式我觉得挺好的,现在写 CPP 很多我都这样写,用 pair 或者 tuple, cpp23 有了 expected,

    go 的问题就是要写太多的 if err != nil , 如果能使用 check, try, ? 关键字或者符号,简化一下代码,那真的非常爽了
    chor02
    chor02
    Apr 28, 2025
    20
    我也不明白为什么不能有默认如果 err 不为空直接返回 err 的方案
    ltaoo1o
    ltaoo1o
    Apr 28, 2025
    21
    第一次接触到这种错误处理方案还是在 rust ,操作返回「结果」而不是「数据」,然后我就在 js 项目中引入了,配合 ts ,代码更健壮了

    ```js
    const r = await dosomething();
    if (r.error) {
    return;
    }
    // <-- 如果没有上面 if r.errror ,直接获取 r.data 在编辑器里面就会给出提示,r.data 可能是空
    console.log(r.data);
    ```
    LawlietZ
    LawlietZ
    Apr 28, 2025
    22
    这个问题讨论了八九年了吧 ?
    server
    server
    Apr 28, 2025
    23
    各有各的优势,各有各的问题,习惯就好了
    huigeer
    huigeer
    Apr 28, 2025
    24
    习惯就好,
    zzhirong
    zzhirong
    OP
    Apr 28, 2025
    25
    @LawlietZ 严格来说, 从 Go 正式发布开始就没停过吧, 后来伴随 Rust, TypeScript 等引入新的语法, 讨论又一次次开始, 我其实就是想看看这么多年过去了, 有无更优雅的方式出现。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   1348 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 59ms · UTC 21:22 · PVG 05:22 · LAX 13:22 · JFK 16:22
    ♥ Do have faith in what you're doing.