Go 錯誤處理:用 panic 取代 err != nil 的模式
本文轉載自微信公眾號「腦子進煎魚了」,作者陳煎魚 。轉載本文請聯系腦子進煎魚了公眾號。
大家好,我是煎魚。
前段時間我分享了文章 《先睹為快,Go2 Error 的掙扎之路》后,和一位朋友進行了一次深度交流,他給我分享了他們項目組對于 Go 錯誤處理的方式調整。
簡單來講,就是在業務代碼中使用 panic 的方式來替代 “永無止境” 的 if err != nil。
我們一起來看看是怎么做,又有什么優缺點,互相學習一輪。
為什么想替換
在 Go 語言中 if err != nil 寫的太多,還要管方法聲明各種,嫌麻煩又不方便:
- err := foo()
- if err != nil {
- //do something..
- return err
- }
- err := foo()
- if err != nil {
- //do something..
- return err
- }
- err := foo()
- if err != nil {
- //do something..
- return err
- }
- err := foo()
- if err != nil {
- //do something..
- return err
- }
上述還是示例代碼,比較直面。若是在工程實踐,還得各種 package 跳來跳去加 if err != nil,講更繁瑣,要去關心整體的上下游。
其余更具體的就不贅述了,可以關注我的公眾號翻看先前的文章。
怎么替換 err != nil
不想寫 if err != nil 的代碼,方式之一就是用 panic 來替代他。
示例代碼如下:
- func GetFish(db *sql.DB, name string) []string {
- rows, err := db.Query("select name from users where `name` = ?", name)
- if err != nil {
- panic(err)
- }
- defer rows.Close()
- var names []string
- for rows.Next() {
- var name string
- err := rows.Scan(&name)
- if err != nil {
- panic(err)
- }
- names = append(names, name)
- }
- err = rows.Err()
- if err != nil {
- panic(err)
- }
- return names
- }
在上述業務代碼中,我們通過 panic 的方式取代了 return err 的函數返回,自然其所關聯的下游業務代碼也就不需要編寫 if err != nil 的代碼:
- func main() {
- fish1 := GetFish(db, "煎魚")
- fish2 := GetFish(db, "咸魚")
- fish3 := GetFish(db, "摸魚")
- ...
- }
同時在轉換為使用 panic 模式的錯誤機制后,我們必須要在外層增加 recover 方法:
- func AppRecovery() gin.HandlerFunc {
- return func(c *gin.Context) {
- defer func() {
- if err := recover(); err != nil {
- if _, ok := err.(AppErr); ok {
- // do something...
- } else {
- panic(err)
- }
- }
- }()
- }
- }
每次 panic 后根據其拋出的錯誤進行斷言,識別是否定制的 AppErr 錯誤類型,若是則可以進行一系列的處理動作。
否則可繼續向上 panic 拋出給頂級的 Recovery 方法進行處理。
這就是一個相對完整的 panic 錯誤鏈路處理了。
優缺點
- 從優點上來講:
- 整體代碼結構看起來更加的簡潔,僅專注于實現邏輯即可。
- 不需要關注和編寫冗雜的 if err != nil 的錯誤處理代碼。
- 從缺點上來講:
- 認知負擔的增加,需要參加項目的每一個新老同學都清楚該模式,要做一個基本規范或培訓。
- 存在一定的性能開銷,每次 panic 都存在用戶態的上下文切換。
- 存在一定的風險性,一旦 panic 沒有 recover 住,就會導致事故。
- Go 官方并不推薦,與 panic 本身的定義相違背,也就是 panic 與 error 的概念混淆。
總結
在今天這篇文章給大家分享了如何使用 panic 的方式來處理 Go 的錯誤,其必然有利必有有弊,需要做一個權衡了。