Go 錯誤處理的爭論,終于有了結(jié)論!
大家好,我是煎魚。
對于 Go 這一門編程語言,Go 核心團(tuán)隊的成員自己心里也非常有數(shù),持續(xù)最久的吐槽就是錯誤處理的冗長。
當(dāng)然,從我們的角度來看,社區(qū)還存在對于 Go 錯誤處理現(xiàn)有機(jī)制不滿意的情況。
近期 Go 官方發(fā)表了《[ On | No ] syntactic support for error handling[1]》正式宣布對錯誤處理機(jī)制的想法和后續(xù)表態(tài)。今天分享給大家。
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
}
這個函數(shù)大概只有 10 余行,但是實際上只有 3-4 行在實際上做邏輯調(diào)用和處理,剩余的 6 行都在處理 err 變量的冗余。
這樣的冗長,就是為什么有關(guān)錯誤處理的吐槽排在每年的 Go 開發(fā)者調(diào)查報告前列的緣由。
圖片
這樣一看,其實就是 Go1 自帶的錯誤處理方式和機(jī)制,就是會被一部份同學(xué)瘋狂吐槽的(也有支持的)
圖片
非常見仁見智了。
Go 核心團(tuán)隊的多輪嘗試
Go 核心團(tuán)隊瘋狂表示多人在多年做過多輪的積極嘗試。
最早可以追溯到 2018 年,時任團(tuán)隊負(fù)責(zé)人的 @Russ Cox 想將該問題的優(yōu)化放進(jìn) Go2 的大籃子里一起解決了。
團(tuán)隊中的 @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
}
但,這被認(rèn)為太復(fù)雜。又沒有辦法繼續(xù)推進(jìn)。僵持住了。
隨后在 2019 年,根據(jù)新的 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
}
但是由于在出現(xiàn)錯誤時,可能會出現(xiàn)在深度嵌套誘發(fā) try,以及 try 會打亂控制流的問題。導(dǎo)致許多人我無法接受 try 提案。并成功被稱為:“臭名昭著”。最終被迫放棄。
又經(jīng)過多年的折騰,@Ian Lance Taylor 參考 Rust 發(fā)布了新的提案《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 還做了小型的用戶實操實驗,當(dāng)時絕大部分參與者都能夠意識到 ? 的作用是什么。他才敢放心(有信心)繼續(xù)推進(jìn)。
但是依然很不幸,這個提案依然被很多的建議和想法給淹沒。沒法得出一個最終的最優(yōu)解。
由此,Go 核心團(tuán)隊的 10+ 年對于錯誤處理機(jī)制探討的推進(jìn)。被迫暫告一段落。甚至引發(fā)了 Go 團(tuán)隊很多的 “反思”。
最終結(jié)論(階段性)
Go 核心團(tuán)隊認(rèn)為,其在過去那么多年,一共提出了 3 個成熟的提案和數(shù)百個社區(qū)提案。但是這些所有的提案,都未能夠得到足夠的社區(qū)支持。
最終(2025 年)Go 官方將決定停止嘗試解決錯誤處理機(jī)制的問題。給出的理由是提案流程里的:
圖片
“提案流程的目標(biāo)是及時就結(jié)果達(dá)成普遍共識。如果提案審查無法在問題跟蹤器上的問題討論中達(dá)成普遍共識,通常的結(jié)果就是拒絕提案。”
同時有兩個非常扎心的事實:
- 截止至目前,沒有任何一個錯誤處理提案達(dá)成共識。全部無一例外都被拒絕了。
- Google Go 團(tuán)隊的資深成員們,也沒有達(dá)成最佳的前進(jìn)共識。(沒有強(qiáng)而有力的共識)
說白了。就是搞不定。沒有最佳的錯誤處理方式。且消耗了太大的精力和時間,官方團(tuán)隊自己也沒有達(dá)成共識。
圖片
在 2025 年 6 月做出了最終的決定:“在可預(yù)見的將來,Go 語言團(tuán)隊將停止針對錯誤處理的語法修改。我們還將關(guān)閉所有主要涉及錯誤處理語法的開放式提案和新提案,不再進(jìn)行進(jìn)一步調(diào)查?!?/p>
總結(jié)
實際上 Go 這一門編程語言的 Go 錯誤處理機(jī)制,一直處于用戶調(diào)查中的風(fēng)頭浪尖。但是會在互聯(lián)網(wǎng)上發(fā)聲的僅僅是一部分人。
但在現(xiàn)實和其他沒發(fā)聲的人里,也有很多支持 Go 不需要改變語法,直接還是用現(xiàn)在的 if err != nil 。也是存在非常多的支持者。(這一點官方在 Google Cloud Next 2025 做了個小型聚會進(jìn)行了相關(guān)討論)
從現(xiàn)實來講,Go 核心團(tuán)隊感覺非常想找到一個完美的錯誤處理機(jī)制,但現(xiàn)階段來看,正因為想一碗水都端平。似乎都無法解決??赡苓€是需要當(dāng)年 rsc 力推 go module 時的決心。
但很可惜,現(xiàn)在和社區(qū)最為親近的 ian 也已經(jīng)離職了,一時半會肯定不會有所改善的了。
參考資料
[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