一文詳細(xì)談?wù)凣oLang的panic和error
前言
首先說(shuō)一下: 錯(cuò)誤指的是可能出現(xiàn)問(wèn)題的地方出現(xiàn)了問(wèn)題。如打開(kāi)件失敗,這種情況在意料之中 。異常指的是不應(yīng)該出現(xiàn)問(wèn)題的地方出現(xiàn)了問(wèn)題。如引用了空指針,這種情況在意料之外
Go 提供兩種錯(cuò)誤處理方式
- 函數(shù)返回
error類(lèi)型對(duì)象判斷錯(cuò)誤 panic異常
1. panic
Go的類(lèi)型系統(tǒng)會(huì)在編譯時(shí)捕獲很多錯(cuò)誤,但有些錯(cuò)誤只能在運(yùn)行時(shí)檢查,如數(shù)組訪(fǎng)問(wèn)越界、空指針引用等。這些運(yùn)行時(shí)錯(cuò)誤會(huì)引起painc異常。
一般而言,當(dāng)panic異常發(fā)生時(shí),程序會(huì)中斷運(yùn)行,并立即執(zhí)行在該goroutine(可以先理解成線(xiàn)程)中被延遲的函數(shù)(defer 機(jī)制)。隨后,程序崩潰并輸出日志信息。日志信息包括panic value和函數(shù)調(diào)用的堆棧跟蹤信息。panic value通常是某種錯(cuò)誤信息。對(duì)于每個(gè)goroutine,日志信息中都會(huì)有與之相對(duì)的,發(fā)生panic時(shí)的函數(shù)調(diào)用堆棧跟蹤信息。通常,我們不需要再次運(yùn)行程序去定位問(wèn)題,日志信息已經(jīng)提供了足夠的診斷依據(jù)。因此,在我們填寫(xiě)問(wèn)題報(bào)告時(shí),一般會(huì)將panic異常和日志信息一并記錄。不是所有的panic異常都來(lái)自運(yùn)行時(shí),直接調(diào)用內(nèi)置的panic函數(shù)也會(huì)引發(fā)panic異常;panic函數(shù)接受任何值作為參數(shù)。當(dāng)某些不應(yīng)該發(fā)生的場(chǎng)景發(fā)生時(shí),我們就應(yīng)該調(diào)用panic。雖然Go的panic機(jī)制類(lèi)似于其他語(yǔ)言的異常,但panic的適用場(chǎng)景有一些不同。由于panic會(huì)引起程序的崩潰,因此panic一般用于嚴(yán)重錯(cuò)誤,如程序內(nèi)部的邏輯不一致。
panic可以手工調(diào)用,但是 Go 官方建議盡量不要使用panic,每一個(gè)異常都應(yīng)該用 error 對(duì)象捕獲。如果異常出現(xiàn)了,但沒(méi)有被捕獲并恢復(fù),Go 程序的執(zhí)行就會(huì)被終止,即便出現(xiàn)異常的位置不在主 Goroutine 中也會(huì)這樣。
總結(jié)來(lái)說(shuō):
panic是一個(gè)嚴(yán)重錯(cuò)誤機(jī)制,它會(huì)導(dǎo)致程序終止,并依次逆序執(zhí)行 panic 所在函數(shù)可能存在的 defer 函數(shù)列表,然后返回該函數(shù)的調(diào)用方。recover 內(nèi)置函數(shù)可用于捕獲 panic,重新恢復(fù)程序正常執(zhí)行流程,但是 recover 函數(shù)只有在 defer 內(nèi)部使用才有效
此外,當(dāng) panic() 觸發(fā)的宕機(jī)發(fā)生時(shí), panic() 后面的代碼將不會(huì)被運(yùn)行,但是在 panic() 函數(shù)前面已經(jīng)運(yùn)行過(guò)的 defer 語(yǔ)句依然會(huì)在宕機(jī)發(fā)生時(shí)發(fā)生作用
2. recover
1. recover 是一個(gè) Go 語(yǔ)言的內(nèi)建函數(shù),可以讓進(jìn)入宕機(jī)流程中的 goroutine 恢復(fù)過(guò)來(lái)。
2. 用來(lái)控制一個(gè)goroutine的panicking行為,捕獲panic,從而影響應(yīng)用的行為
3. 一般的調(diào)用建議
a). 在defer函數(shù)中,通過(guò)recever來(lái)終止一個(gè)gojroutine的panicking過(guò)程,從而恢復(fù)正常代碼的執(zhí)行
b). 可以獲取通過(guò)panic傳遞的error
簡(jiǎn)單來(lái)講:go中可以?huà)伋鲆粋€(gè)panic的異常,然后在defer中通過(guò)recover捕獲這個(gè)異常,然后正常處理。
4. 在正常的執(zhí)行過(guò)程中,調(diào)用 recover 會(huì)返回 nil 并且沒(méi)有其他任何效果;
注意:利用recover處理panic指令,defer必須在panic之前聲明,否則當(dāng)panic時(shí),recover無(wú)法捕獲到panic.
總結(jié)來(lái)說(shuō) Go 語(yǔ)言沒(méi)有異常系統(tǒng),其使用 panic 觸發(fā)宕機(jī)類(lèi)似于其他語(yǔ)言的拋出異常, recover 的宕機(jī)恢復(fù)機(jī)制就對(duì)應(yīng)其它語(yǔ)言中的 try/catch 機(jī)制。
panic 和 recover 的關(guān)系
panic 和 recover 的組合有如下特性:
有 panic 沒(méi) recover ,程序宕機(jī)。
有 panic 也有 recover ,程序不會(huì)宕機(jī),執(zhí)行完對(duì)應(yīng)的 defer 后,從宕機(jī)點(diǎn)退出當(dāng)前函數(shù)后繼續(xù)執(zhí)行。
注意:在 panic 觸發(fā)的 defer 函數(shù)內(nèi),可以繼續(xù)調(diào)用 panic ,進(jìn)一步將錯(cuò)誤外拋,直到程序整體崩潰。如果想在捕獲錯(cuò)誤時(shí)設(shè)置當(dāng)前函數(shù)的返回值,可以對(duì)返回值使用命名返回值方式直接進(jìn)行設(shè)置。
示例:
package main
func test() {
defer func() {
if err := recover(); err != nil { // recover 捕獲錯(cuò)誤。
println(err.(string)) // 將 interface{} 轉(zhuǎn)型為具體類(lèi)型。
}
}()
panic("panic error!") // panic 拋出錯(cuò)誤
}
func main() {
test()
}3. error
go中的錯(cuò)誤處理,是通過(guò)返回值的形式來(lái)出來(lái),要么你忽略,要么你處理(處理也可以是繼續(xù)返回給調(diào)用者),對(duì)于golang這種設(shè)計(jì)方式,我們會(huì)在代碼中寫(xiě)大量的if判斷,以便做出決定。
對(duì)于err如果是nil就代表沒(méi)有錯(cuò)誤,如果不是nil就代表程序出問(wèn)題了,需要對(duì)錯(cuò)誤進(jìn)行處理了。
示例:
func main() {
conent,err:=ioutil.ReadFile("filepath")
if err !=nil{
//錯(cuò)誤處理
}else {
fmt.Println(string(conent))
}
}此外,error類(lèi)型是go語(yǔ)言的一種內(nèi)置類(lèi)型,使用的時(shí)候不用特定去import,他本質(zhì)上是一個(gè)接口,
type error interface{
Error() string //Error()是每一個(gè)訂制的error對(duì)象需要填充的錯(cuò)誤消息,可以理解成是一個(gè)字段Error
}總結(jié)
到此這篇關(guān)于GoLang中panic和error的文章就介紹到這了,更多相關(guān)GoLang的panic和error內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺析Go語(yǔ)言容器之?dāng)?shù)組和切片的使用
在?Java?的核心庫(kù)中,集合框架可謂鼎鼎大名:Array?、List、Set等等,隨便拎一個(gè)出來(lái)都值得開(kāi)發(fā)者好好學(xué)習(xí)如何使用甚至是背后的設(shè)計(jì)源碼。雖然Go語(yǔ)言沒(méi)有如此豐富的容器類(lèi)型,但也有一些基本的容器供開(kāi)發(fā)者使用,接下來(lái)讓我們認(rèn)識(shí)一下這些容器類(lèi)型吧2022-11-11
go語(yǔ)言接口的定義和實(shí)現(xiàn)簡(jiǎn)單分享
這篇文章主要介紹了go語(yǔ)言接口的定義和實(shí)現(xiàn)簡(jiǎn)單分享的相關(guān)資料,需要的朋友可以參考下2023-08-08
Go?Excelize?API源碼閱讀Close及NewSheet方法示例解析
這篇文章主要為大家介紹了Go?Excelize?API源碼閱讀Close及NewSheet方法示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08
對(duì)Golang中的runtime.Caller使用說(shuō)明
這篇文章主要介紹了對(duì)Golang中的runtime.Caller使用說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12
go語(yǔ)言中切片的長(zhǎng)度和容量的區(qū)別
這篇文章主要介紹了go語(yǔ)言中切片的長(zhǎng)度和容量的區(qū)別,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-04-04
GoFrame框架gset交差并補(bǔ)集使用實(shí)例
這篇文章主要為大家介紹了GoFrame框架gset交差并補(bǔ)集使用實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
golang?debug調(diào)試的實(shí)現(xiàn)
本文主要介紹了使用Go語(yǔ)言進(jìn)行本地調(diào)試和遠(yuǎn)程調(diào)試,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-12-12

