Golang中錯誤處理機(jī)制詳解
Golang錯誤處理機(jī)制
panic異常
panic異常
- Go的類型系統(tǒng)會在編譯時捕獲很多錯誤,但有些錯誤只能在運(yùn)行時檢查,比如除零錯誤、數(shù)組訪問越界、空指針引用等,這些運(yùn)行時錯誤會引起panic異常。
- 當(dāng)panic異常發(fā)生時,程序會中斷運(yùn)行,并立即執(zhí)行當(dāng)前函數(shù)中的defer語句,然后程序會從調(diào)用棧中逐級返回,返回同時執(zhí)行各級函數(shù)中的defer語句,直到panic被捕獲或程序終止。
例如,下面的代碼在運(yùn)行過程中,由于存在除零錯誤將導(dǎo)致panic異常。如下:
package main
import "fmt"
func Division(num1 int, num2 int) int {
defer fmt.Println("Division defer...")
return num1 / num2
}
func main() {
defer fmt.Println("main defer...")
// panic異常
result := Division(10, 0)
fmt.Printf("result = %d\n", result)
fmt.Println("other code...")
}
運(yùn)行代碼后可以看到,main函數(shù)中調(diào)用Division函數(shù)之后的代碼沒有被執(zhí)行。但在程序退出之前,Division和main函數(shù)中的defer語句被逐一執(zhí)行。如下:

recover捕獲異常
recover捕獲異常
- 當(dāng)觸發(fā)panic異常時,我們希望程序可以繼續(xù)運(yùn)行,并希望在觸發(fā)異常后,能夠執(zhí)行某些操作,比如給管理員發(fā)送一條告警信息。
- 在Go中,捕獲異常通過在defer中調(diào)用內(nèi)建函數(shù)recover實(shí)現(xiàn),recover函數(shù)會使程序從panic中恢復(fù),并返回觸發(fā)panic的值,如果程序沒有發(fā)生panic,則recover調(diào)用將會返回nil。
- 需要注意的是,當(dāng)異常被捕獲后,觸發(fā)panic異常的函數(shù)也不會繼續(xù)運(yùn)行,但能正常返回。
例如,下面在Division函數(shù)的defer中捕獲了panic異常,并將觸發(fā)panic異常的值進(jìn)行了返回。如下:
package main
import "fmt"
func Division(num1 int, num2 int) (result int, err error) {
defer func() {
if r := recover(); r != nil {
err = r.(error) // 類型斷言,將r轉(zhuǎn)換為error類型(后續(xù)介紹)
}
}()
return num1 / num2, nil
}
func main() {
// recover捕獲異常
result, err := Division(10, 0)
if err != nil {
fmt.Printf("division operation error, err = %v\n", err)
} else {
fmt.Printf("result = %d\n", result)
}
}
運(yùn)行代碼后可以看到,由于panic異常被捕獲使得Division函數(shù)正常返回,同時main函數(shù)后續(xù)的代碼也被正常執(zhí)行。如下:

由于panic異常會逐級拋出,直到異常被捕獲或程序終止,因此可以選擇在調(diào)用鏈的任意一個函數(shù)中對panic進(jìn)行捕獲。如下:
package main
import "fmt"
func Division(num1 int, num2 int) int {
return num1 / num2
}
func main() {
// recover捕獲異常
defer func() {
if err := recover(); err != nil {
fmt.Printf("recoverd from panic, err = %v\n", err)
}
}()
result := Division(10, 0)
fmt.Printf("result = %d\n", result)
fmt.Println("other code...")
}
由于Division函數(shù)中沒有對panic進(jìn)行捕獲,導(dǎo)致main函數(shù)觸發(fā)panic異常,雖然在main函數(shù)中對panic進(jìn)行了捕獲,但main函數(shù)的后續(xù)代碼將不會被執(zhí)行。如下:

自定義錯誤
自定義錯誤
- 不是只有程序在運(yùn)行時出現(xiàn)錯誤才能觸發(fā)panic異常,通過調(diào)用內(nèi)建函數(shù)panic也能觸發(fā)panic異常。
- panic函數(shù)能夠接收任何類型的值作為參數(shù),并在觸發(fā)panic時將其作為觸發(fā)panic的值。
- 觸發(fā)panic的值通常是error類型的,通過errors包中的New函數(shù)可以創(chuàng)建一個error類型的錯誤值,該函數(shù)接收一個string類型的參數(shù),并返回創(chuàng)建的error類型的錯誤值。
例如,我們規(guī)定除數(shù)不能為20,否則觸發(fā)panic異常。如下:
package main
import (
"errors"
"fmt"
)
func Division(num1 int, num2 int) (result int, err error) {
defer func() {
if r := recover(); r != nil {
err = r.(error)
}
}()
if num2 == 20 {
panic(errors.New("integer divide by 20"))
}
return num1 / num2, nil
}
func main() {
// recover捕獲異常
result, err := Division(10, 20)
if err != nil {
fmt.Printf("division operation error, err = %v\n", err)
} else {
fmt.Printf("result = %d\n", result)
}
}
運(yùn)行代碼后可以看到,通過panic函數(shù)觸發(fā)的異常也能夠成功被捕獲。如下:

說明一下: 通過recover將panic捕獲后,可以繼續(xù)通過調(diào)用panic函數(shù)將panic再次拋出,使其傳播到更高層的調(diào)用棧進(jìn)行進(jìn)一步處理,這叫做異常的重新拋出。
到此這篇關(guān)于Golang中錯誤處理機(jī)制詳解的文章就介紹到這了,更多相關(guān)Golang錯誤處理機(jī)制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
golang協(xié)程關(guān)閉踩坑實(shí)戰(zhàn)記錄
協(xié)程(coroutine)是Go語言中的輕量級線程實(shí)現(xiàn),下面這篇文章主要給大家介紹了關(guān)于golang協(xié)程關(guān)閉踩坑的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-03-03
Golang中實(shí)現(xiàn)數(shù)據(jù)脫敏處理的go-mask包分享
這篇文章主要是來和大家分享一個在輸出中對敏感數(shù)據(jù)進(jìn)行脫敏的工作包:go-mask,可以將敏感信息輸出的時候替換成星號或其他字符,感興趣的小編可以跟隨小編一起了解下2023-05-05
如何判斷Golang接口是否實(shí)現(xiàn)的操作
這篇文章主要介紹了如何判斷Golang接口是否實(shí)現(xiàn)的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12
go 迭代string數(shù)組操作 go for string[]
這篇文章主要介紹了go 迭代string數(shù)組操作 go for string[],具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12
Golang如何對cron進(jìn)行二次封裝實(shí)現(xiàn)指定時間執(zhí)行定時任務(wù)
這篇文章主要介紹了Golang如何對cron進(jìn)行二次封裝實(shí)現(xiàn)指定時間執(zhí)行定時任務(wù)問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2025-06-06
Go1.21新增內(nèi)置函數(shù)(built-in?functions)詳解
Go?1.21新增的內(nèi)置函數(shù)分別是?min、max?和?clear,這篇文章主要帶大家一起了解一下這幾個函數(shù)的用途和使用示例,感興趣的小伙伴可以學(xué)習(xí)一下2023-08-08

