Go語言中panic和recover的實現(xiàn)
Go 語言的 panic 和 recover 是兩種用于處理異常的機制。
它們允許在程序運行過程中進行錯誤處理,特別是處理那些不可恢復(fù)的錯誤和恢復(fù)程序的執(zhí)行。
panic 和 recover 并不像其他語言中的 try-catch 機制那樣常見,而是提供了控制程序流程的一種方法。
panic 機制
panic 用于表示程序遇到了一個不可恢復(fù)的錯誤,或者程序處于一個不應(yīng)繼續(xù)執(zhí)行的狀態(tài)。它會觸發(fā)運行時的異常,并停止當前函數(shù)的執(zhí)行,直到調(diào)用 recover 或程序退出。
1.1 panic 的使用
當你遇到一個嚴重的錯誤或不合法的操作時,可以調(diào)用 panic 來終止當前函數(shù)的執(zhí)行,并開始觸發(fā)一系列的 defer 函數(shù)。
panic 會導(dǎo)致當前函數(shù)的執(zhí)行停止,并且會遞歸地向上層函數(shù)傳播,直到程序結(jié)束或者有 recover 恢復(fù)它。
使用 panic 終止程序
func divide(a, b int) int {
if b == 0 {
panic("division by zero") // 如果除數(shù)為零,拋出 panic
}
return a / b
}
func main() {
fmt.Println("Starting program")
// 這里會觸發(fā) panic
result := divide(10, 0)
fmt.Println("Result:", result) // 這行代碼不會執(zhí)行
}
當 b == 0 時,panic 被觸發(fā),程序會停止當前函數(shù)的執(zhí)行,并開始遞歸傳播。
panic 的錯誤信息是 "division by zero",這將顯示在控制臺。
調(diào)用 panic 后,程序停止執(zhí)行,任何后續(xù)代碼都不會被執(zhí)行,除非在調(diào)用鏈中有 recover。
recover 機制
recover 是 Go 語言中用來從 panic 中恢復(fù)的函數(shù)。它只能在 defer 中使用。當 recover 被調(diào)用時,它會捕獲到正在執(zhí)行的 panic,并停止 panic 繼續(xù)傳播,恢復(fù)程序的執(zhí)行。
2.1 recover 的使用
recover 會返回 panic 時傳遞的值,并恢復(fù)程序的正常執(zhí)行。
如果 recover 沒有在 panic 發(fā)生時被調(diào)用,panic 會繼續(xù)向上傳播,直到程序退出。
只有在 defer 函數(shù)內(nèi)部,recover 才能捕獲到 panic。
使用 recover 恢復(fù)程序
func divide(a, b int) int {
if b == 0 {
panic("division by zero") // 如果除數(shù)為零,拋出 panic
}
return a / b
}
func safeDivide(a, b int) (result int, err string) {
defer func() {
if r := recover(); r != nil {
err = fmt.Sprintf("Recovered from panic: %v", r)
}
}()
result = divide(a, b) // 可能會觸發(fā) panic
return
}
func main() {
result, err := safeDivide(10, 0)
if err != "" {
fmt.Println("Error:", err)
} else {
fmt.Println("Result:", result)
}
}
Error: Recovered from panic: division by zero
safeDivide 函數(shù)嘗試執(zhí)行 divide,如果 divide 觸發(fā)了 panic,recover 會捕獲到并停止 panic 繼續(xù)傳播。
defer 中的匿名函數(shù)通過 recover() 捕獲 panic,并將 panic 的信息作為錯誤返回。
程序恢復(fù)執(zhí)行并返回錯誤信息,而不會崩潰。
panic 和 recover 的工作流程
panic 的傳播:
當 panic 被觸發(fā)時,Go 會立即停止當前函數(shù)的執(zhí)行,并開始遞歸地向上傳播 panic。
每次 panic 傳播時,都會執(zhí)行當前函數(shù)的所有 defer 語句。
recover 捕獲 panic:
如果在某個 defer 語句中調(diào)用 recover,它將會捕獲當前的 panic 并停止 panic 的傳播。
recover 返回 panic 時傳遞的參數(shù),通常是一個錯誤信息。
如果沒有 recover 捕獲,panic 將繼續(xù)傳播,直到程序退出。
panic 和 recover 使用的注意事項
不要濫用 panic 和 recover:Go 語言的設(shè)計原則鼓勵使用顯式的錯誤處理機制(例如返回錯誤值),而不是通過 panic 來表示常規(guī)錯誤。panic 應(yīng)該只用于處理那些程序無法恢復(fù)的錯誤(例如數(shù)組越界、無法恢復(fù)的邏輯錯誤等)。
defer 和 recover:recover 必須在 defer 函數(shù)中調(diào)用才能有效。如果 recover 不在 defer 中,它將無法捕獲到 panic。
panic 和 recover 用于同步代碼:panic 和 recover 通常用于同步函數(shù)的錯誤處理。它們不能用于并發(fā)的錯誤處理(例如 goroutine 中的錯誤處理)。對于并發(fā)程序,Go 更傾向于通過返回錯誤值來處理錯誤。
panic 和 recover 的機制引入了較高的開銷,通常應(yīng)避免在高頻調(diào)用的代碼中使用 panic。它們更適合處理那些異常、不可恢復(fù)的錯誤,而不是正常的程序流程控制。
實際應(yīng)用中的使用場景
panic 的場景:當程序遇到無法繼續(xù)執(zhí)行的嚴重錯誤時,調(diào)用 panic。例如:空指針解引用、數(shù)組越界等。
recover 的場景:當你希望在程序中捕獲并恢復(fù)某些不可預(yù)見的錯誤時,使用 recover。常見的場景包括:Web 服務(wù)器的中間件處理、數(shù)據(jù)庫事務(wù)的回滾等。
Web 服務(wù)器的 panic 恢復(fù)
func handler(w http.ResponseWriter, r *http.Request) {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
http.Error(w, "Internal server error", http.StatusInternalServerError)
}
}()
panic("Something went wrong") // 模擬一個 panic
}
func main() {
http.HandleFunc("/", handler)
fmt.Println("Starting server at :8080...")
if err := http.ListenAndServe(":8080", nil); err != nil {
fmt.Println("Server failed:", err)
}
}
服務(wù)器啟動:當你運行程序時,main 函數(shù)啟動 HTTP 服務(wù)器并監(jiān)聽端口 8080。
觸發(fā) panic:當你訪問根路徑(http://localhost:8080/)時,handler 函數(shù)會被觸發(fā)。在 handler 函數(shù)中,程序會故意執(zhí)行 panic("Something went wrong"),模擬一個錯誤的發(fā)生。
recover 捕獲 panic:panic 觸發(fā)后,程序會立即停止當前函數(shù)的執(zhí)行。此時,defer 語句中的匿名函數(shù)被調(diào)用,recover 會捕獲到 panic,然后通過 http.Error 返回 500 錯誤響應(yīng)給客戶端。
恢復(fù)并繼續(xù)執(zhí)行:由于 recover 捕獲并處理了 panic,程序不會崩潰,而是繼續(xù)執(zhí)行。到此這篇關(guān)于Go語言中panic和recover的實現(xiàn)的文章就介紹到這了,更多相關(guān)Go語言 panic和recover內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go 1.23中Timer無buffer的實現(xiàn)方式詳解
在 Go 1.23 中,Timer 的實現(xiàn)通常是通過 time 包提供的 time.Timer 類型來實現(xiàn)的,本文主要介紹了Go 1.23中Timer無buffer的實現(xiàn)方式,需要的可以了解下2025-03-03
Go語言基礎(chǔ)語法和基本數(shù)據(jù)類型知識鞏固
這篇文章主要為大家介紹了Go語言基礎(chǔ)語法和基本數(shù)據(jù)類型知識鞏固,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-11-11
go?defer?return?panic?執(zhí)行順序示例詳解
這篇文章主要介紹了go?defer?return?panic?執(zhí)行順序,本文通過示例代碼給大家介紹的非常詳細,對大家的學(xué)習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-01-01
golang解析網(wǎng)頁利器goquery的使用方法
這篇文章主要給大家介紹了關(guān)于golang解析網(wǎng)頁利器goquery的使用方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友可以參考借鑒,下面來一起學(xué)習學(xué)習吧。2017-09-09

