Go 錯誤處理:用 panic 取代 err != nil 的模式

如有任何問題或建議,歡迎及時交流和碰撞。個人公衆號是 【腦子進煎魚了】,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,總的來說比較繁瑣,要去關心總體的上下游。更具體的就不贅述了,能夠翻看我先前的文章。架構

怎麼替換 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 住,就會致使事故。
    • Go 官方並不推薦,與 panic 自己的定義相違背,也就是 panicerror 的概念混淆。

總結

在今天這篇文章給你們分享瞭如何使用 panic 的方式來處理 Go 的錯誤,其必然有利必有有弊,須要作一個權衡了。

大家團隊有沒有爲了 Go 錯誤處理作過什麼新的調整呢?歡迎在留言區交流和分享。

個人公衆號

分享 Go 語言、微服務架構和奇怪的系統設計,歡迎你們關注個人公衆號和我進行交流和溝通。

最好的關係是互相成就,各位的點贊就是煎魚創做的最大動力,感謝支持。

相關文章
相關標籤/搜索