Go 错误处理的争论,终于有了结论!!

大家好,我是煎鱼。

对于 Go 这一门编程语言,Go 核心团队的成员自己心里也非常有数,持续最久的吐槽就是错误处理的冗长。

当然,从我们的角度来看,社区还存在对于 Go 错误处理现有机制不满意的情况。

近期 Go 官方发表了《[ On | No ] syntactic support for error handling[1]》正式宣布对错误处理机制的想法和后续表态。今天分享给大家。

Go1 错误处理的 “冗长” 例子

Go 的 if err != nil 的最短例子如下:

x, err := call()
if err != nil {
        // handle err
}

更常见的代码例子如下:

func printSum(a, b string) error {
    x, err := strconv.Atoi(a)
    if err != nil {
        return err
    }
    y, err := strconv.Atoi(b)
    if err != nil {
        return err
    }
    fmt.Println("result:", x + y)
    return nil
}

这个函数大概只有 10 余行,但是实际上只有 3-4 行在实际上做逻辑调用和处理,剩余的 6 行都在处理 err 变量的冗余。

这样的冗长,就是为什么有关错误处理的吐槽排在每年的 Go 开发者调查报告前列的缘由。

这样一看,其实就是 Go1 自带的错误处理方式和机制,就是会被一部份同学疯狂吐槽的(也有支持的)

非常见仁见智了。

Go 核心团队的多轮尝试

Go 核心团队疯狂表示多人在多年做过多轮的积极尝试。

最早可以追溯到 2018 年,时任团队负责人的 @Russ Cox 想将该问题的优化放进 Go2 的大篮子里一起解决了。

团队中的 @Marcel van Lohuizen 提出了《Error Handling — Draft Design[2]》的提案,示例代码如下:

// printSum implementation using the proposed check/handle mechanism.
func printSum(a, b string) error {
    handle err { return err }
    x := check strconv.Atoi(a)
    y := check strconv.Atoi(b)
    fmt.Println("result:", x + y)
    return nil
}

但,这被认为太复杂。又没有办法继续推进。僵持住了。

随后在 2019 年,根据新的 try 提案《Proposal: A built-in Go error check function, try[3]》又做了改善。

示例代码如下:

// printSum implementation using the proposed try mechanism.
func printSum(a, b string) error {
    // use a defer statement to augment errors before returning
    x := try(strconv.Atoi(a))
    y := try(strconv.Atoi(b))
    fmt.Println("result:", x + y)
    return nil
}

但是由于在出现错误时,可能会出现在深度嵌套诱发 try,以及 try 会打乱控制流的问题。导致许多人我无法接受 try 提案。并成功被称为:“臭名昭著”。最终被迫放弃。

又经过多年的折腾,@Ian Lance Taylor 参考 Rust 发布了新的提案《proposal: spec: reduce error handling boilerplate using ?[4]》。

示例代码如下:

// printSum implementation using the proposed "?" statements.
func printSum(a, b string) error {
    x := strconv.Atoi(a) ?
    y := strconv.Atoi(b) ?
    fmt.Println("result:", x + y)
    return nil
}

实际上 @Ian Lance Taylor 还做了小型的用户实操实验,当时绝大部分参与者都能够意识到 ? 的作用是什么。他才敢放心(有信心)继续推进。

但是依然很不幸,这个提案依然被很多的建议和想法给淹没。没法得出一个最终的最优解。

由此,Go 核心团队的 10+ 年对于错误处理机制探讨的推进。被迫暂告一段落。甚至引发了 Go 团队很多的 “反思”。

最终结论(阶段性)

Go 核心团队认为,其在过去那么多年,一共提出了 3 个成熟的提案和数百个社区提案。但是这些所有的提案,都未能够得到足够的社区支持。

最终(2025 年)Go 官方将决定停止尝试解决错误处理机制的问题。给出的理由是提案流程里的:

“提案流程的目标是及时就结果达成普遍共识。如果提案审查无法在问题跟踪器上的问题讨论中达成普遍共识,通常的结果就是拒绝提案。”

同时有两个非常扎心的事实:

  • 截止至目前,没有任何一个错误处理提案达成共识。全部无一例外都被拒绝了。

  • Google Go 团队的资深成员们,也没有达成最佳的前进共识。(没有强而有力的共识)

说白了。就是搞不定。没有最佳的错误处理方式。且消耗了太大的精力和时间,官方团队自己也没有达成共识。

在 2025 年 6 月做出了最终的决定:“在可预见的将来,Go 语言团队将停止针对错误处理的语法修改。我们还将关闭所有主要涉及错误处理语法的开放式提案和新提案,不再进行进一步调查。”

总结

实际上 Go 这一门编程语言的 Go 错误处理机制,一直处于用户调查中的风头浪尖。但是会在互联网上发声的仅仅是一部分人。

但在现实和其他没发声的人里,也有很多支持 Go 不需要改变语法,直接还是用现在的 if err != nil 。也是存在非常多的支持者。(这一点官方在 Google Cloud Next 2025 做了个小型聚会进行了相关讨论)

从现实来讲,Go 核心团队感觉非常想找到一个完美的错误处理机制,但现阶段来看,正因为想一碗水都端平。似乎都无法解决。可能还是需要当年 rsc 力推 go module 时的决心。

但很可惜,现在和社区最为亲近的 ian 也已经离职了,一时半会肯定不会有所改善的了。

参考资料

[1] 

[ On | No ] syntactic support for error handling: https://go.dev/blog/error-syntax

[2] 

Error Handling — Draft Design: https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling.md

[3] 

Proposal: A built-in Go error check function, try: https://go.googlesource.com/proposal/+/master/design/32437-try-builtin.md

[4] 

proposal: spec: reduce error handling boilerplate using ?: https://github.com/golang/go/issues/71203

关注和加煎鱼微信,

一手消息和知识,拉你进技术交流群👇

你好,我是煎鱼,出版过 Go 畅销书《Go 语言编程之旅》,再到获得 GOP(Go 领域最有观点专家)荣誉,点击蓝字查看我的出书之路

日常分享高质量文章,输出 Go 面试、工作经验、架构设计,加微信拉读者交流群,和大家交流!

原创不易 点赞支持

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值