如有任何問題或建議,歡迎及時交流和碰撞。個人公衆號是 【腦子進煎魚了】,GitHub 地址: https://github.com/eddycjy。
前段時間我分享了文章 《先睹爲快,Go2 Error 的掙扎之路》後,和一位朋友進行了一次深度交流,他給我分享了他們項目組對於 Go 錯誤處理的方式調整。git
簡單來說,就是在業務代碼中使用 panic
的方式來替代 「永無止境」 的 if err != nil
。這就是今天本文的重點內容,咱們一塊兒來看看是怎麼作,又有什麼優缺點。github
在 Go 語言中 if err != nil
寫的太多,還要管方法聲明各類,嫌麻煩又不方便:sql
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
,總的來說比較繁瑣,要去關心總體的上下游。更具體的就不贅述了,能夠翻看我先前的文章。架構
不想寫 if err != nil
的代碼,方式之一就是用 panic
來替代他。示例代碼以下:app
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
錯誤鏈路處理了。spa
從優勢上來說:設計
if err != nil
的錯誤處理代碼。從缺點上來說:
panic
都存在用戶態的上下文切換。panic
沒有 recover
住,就會致使事故。panic
自己的定義相違背,也就是 panic
與 error
的概念混淆。在今天這篇文章給你們分享瞭如何使用 panic
的方式來處理 Go 的錯誤,其必然有利必有有弊,須要作一個權衡了。
大家團隊有沒有爲了 Go 錯誤處理作過什麼新的調整呢?歡迎在留言區交流和分享。
分享 Go 語言、微服務架構和奇怪的系統設計,歡迎你們關注個人公衆號和我進行交流和溝通。
最好的關係是互相成就,各位的點贊就是煎魚創做的最大動力,感謝支持。