有點(diǎn)不優(yōu)雅:Go 的 panic 與 recover

現(xiàn)作為 一名 Go 的開發(fā)者,每天都在與 if err != nil 打交道,或許這已經(jīng)成了 Go 的標(biāo)志性特征。但每當(dāng)遇到 panic 時(shí),程序直接崩潰重啟,讓人皺起眉頭——這個(gè)是不是得用recover處理一下了?

一、go有沒有異常機(jī)制?

其他語言都有成熟的異常處理機(jī)制:Java 的 try-catch,Python 的 except,JavaScript 的 try-catch。而 Go 呢?它說:「我們不需要異常,錯(cuò)誤也是值!」

結(jié)果卻偷偷提供了 panicrecover

  • panic 會立刻中斷當(dāng)前函數(shù)的正常執(zhí)行,沿著調(diào)用棧向上回溯,依次執(zhí)行已注冊的 defer
  • recover 在 panic 向上傳播過程中截獲它,讓程序恢復(fù)正常執(zhí)行
  • 如果沒有 recover,程序會崩潰退出
// 日常錯(cuò)誤處理:無處不在的 if err != nil
func readFile(filename string) ([]byte, error) {
    file, err := os.Open(filename)
    if err != nil {
        return nil, err
    }
    defer file.Close()
    // 更多 if err != nil...
}

// 但偶爾又會看到這種「異類」
func riskyOperation() {
    defer func() {
        if r := recover(); r != nil {
            log.Println("程序差點(diǎn)崩了:", r)
        }
    }()
    // 某些可能會 panic 的操作
    panic("Oops!")
}

二、Web 應(yīng)用panic噩夢

在 Web 開發(fā)中,一個(gè)未 recover 的 panic 就意味著整個(gè)服務(wù)進(jìn)程崩潰!你知道在生產(chǎn)環(huán)境看到「502 Bad Gateway」是因?yàn)橐粋€(gè)沒捕獲的 panic 時(shí)有多絕望嗎?

func main() {
    http.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) {
        // 萬一這里 panic 了...
        panic("數(shù)據(jù)庫連接失敗!")
    })
    
    log.Fatal(http.ListenAndServe(":8080", nil))
}

于是我們不得不在每個(gè) handler 里寫重復(fù)的 recover 代碼,不想讓服務(wù)直接崩潰~

func safeHandler(h http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        defer func() {
            if r := recover(); r != nil {
                log.Printf("捕獲到 panic: %v", r)
                http.Error(w, "內(nèi)部服務(wù)器錯(cuò)誤", http.StatusInternalServerError)
            }
        }()
        h(w, r)
    }
}

三、panic/recover 到底該用在什么地方?

在大多數(shù)情況下,清晰的錯(cuò)誤返回值比隱式的 panic/recover更符合 Go 的哲學(xué)。只有在真正異常的情況下,才應(yīng)該考慮使用 panic/recover。

  1. 真正不可恢復(fù)的錯(cuò)誤:比如程序啟動(dòng)時(shí)配置檢查失敗
  2. 防止程序崩潰:在頂層捕獲 panic,保證服務(wù)不會因?yàn)橐粋€(gè)請求而完全宕機(jī)
  3. 復(fù)雜嵌套的退出:在某些深層遞歸或復(fù)雜操作中,panic 可以作為一種「快速退出」機(jī)制
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 大山的的孩子 前 言 ...
    一碩閱讀 95評論 0 0
  • 風(fēng)起時(shí)愛已荒蕪 第一章 首富裴景辭破產(chǎn)后做的第一件事,就是提出了離婚。 盛青禾很早就收到了那份離婚協(xié)議。 她知道,...
    熊熊不熊1閱讀 315評論 0 0
  • 在養(yǎng)生的諸多環(huán)節(jié)中,合理飲食占據(jù)著極為重要的地位。每日清晨,當(dāng)?shù)谝豢|陽光灑進(jìn)廚房,為自己準(zhǔn)備一份營養(yǎng)豐富的早餐,便...
    清泉石上流401a閱讀 69評論 0 0
  • 《仁心俱樂部》結(jié)局,CP都圓滿,全員都解脫。該談戀愛的談戀愛,該升職的升職,令人欣慰。 我比較滿意這個(gè)結(jié)局。病愈后...
    娛娛魚閱讀 1,223評論 0 3
  • 我的人生.我的一生可能一本書也寫不完.人的一生太苦了.真是酸甜苦辣咸樣樣俱全...我出生在一個(gè)很窮的家庭.在我董事...
    c7128f0a221b閱讀 55評論 0 0

友情鏈接更多精彩內(nèi)容