Go 新提案:用 #err 標識符去做錯誤處理!
大家好,我是煎魚。
前幾天看 Reddit 社區(qū)里的討論,發(fā)現 Go 這一門編程語言,錯誤處理永遠是討論的議題之一。本著追蹤網友腦洞 Proposal 的基礎上,周末看到個被反對比較多的 Go2 錯誤處理提案。
圖片
今天結合分享給大家,好的壞的都可以看看別人的想法。
問題背景
在 Go 這門編程語言中,錯誤處理機制主要是依賴于 if err != nil 的方式。因此在對函數做一定的封裝后。
代碼最終常呈現出以下樣子:
jy1, err := GetFoo()
if err != nil {
return err
}
jy2, err := SliceTheBar(varFoo)
if err != nil {
return err
}
err := CheckBarSlice(sliceBar)
if err != nil {
return err
}
...
有部分開發(fā)者會認為這比較的丑陋、混亂且難以閱讀。
圖片
有人戲稱一個 Go 工程里有 60% 的代碼是 if err != nil,為此我見過直接用 panic 來做錯誤處理的團隊。
新提案:用 #err 作為標識符
提案的提出者 @mainjzb,主要的設計目標是:將 # 作為標識位,格式上是把 #xxx 作為程序處理錯誤的標識符。幫助開發(fā)者閱讀代碼并簡化代碼。
原本 Go 錯誤處理方式,如下老代碼:
n, err := io.Write(x)
n, _ := io.Write(x)
n, err := io.Write(x)
if err != nil {
return 0, err
}
n, err := io.Write(x)
if err != nil {
return 0, fmt.Error("tcp closed: %w", err)
}
n, err := io.Write(x)
if err != nil{
panic(err)
}
使用上述提案后的錯誤標識改造后,新的代碼如下:
// 1. err as value
n := io.Write(x) #err
// 2. ignore error
n := io.Write(x) #@ignore
// 3. return error immediately、
n := io.Write(x) #@done
// 4. wrap additional information
n := io.Write(x) #@wrap("tcp closed: %w")
// 5. panic err
n := io.Write(x) #@must
結合上述提案改進后的代碼,原作者給出了以下幾種 # 標識符的想法:
- #err 標識符:err 變量作為值,一切與以前 error 一樣。只是變成了 #err 的標識用法。
- #@ignore 標識符:使忽略錯誤變得比以前更易讀,也可以用附加的描述信息便于開發(fā)者閱讀。
- #@done 標識符:直接返回錯誤信息。很多時候(特別是在庫中),只需要返回錯誤,無需執(zhí)行任何操作。例如:url.parseAuthority。
- #@wrap 標識符:在 error 上附帶更多的錯誤信息,例如:#@wrap 在實際業(yè)務代碼中可以寫作 #@wrap("io.Wirite err:")。
- #@must 標識符:這個標識符可以在產生錯誤時,直接觸發(fā) panic 事件。
總結
這個提案的作者有多門編程語言經驗,本次提出的新提案,很明顯是瞄著解決 Go 這門編程語言中的 if err != nil 的不斷重復的代碼內容的方向去的。
雖然原提案作者另辟蹊徑,通過增加 #err 這類標識符來直接扭轉錯誤處理,解決了大量重復 err 代碼。
圖片
但最終與 Go 語言的其他部分過于不適。已經被 ban 了。謹記:想要優(yōu)化 GO 的 if err != nil 還得要考慮整體適合度,不能一廂情愿。