雖然在使用Golang的時(shí)候發(fā)現(xiàn)沒有try catch這種錯(cuò)誤處理機(jī)制但是想一想golang作為一門優(yōu)雅的語(yǔ)言,似乎也是情理之中。因?yàn)樵趈ava中 throws在函數(shù)簽名中有一個(gè)關(guān)鍵字,旨在使異常流程比較簡(jiǎn)潔,但是一旦預(yù)期的異常數(shù)量增加,就很難準(zhǔn)確捕捉到具體異常所在。
雖然golang中并不提供try catch的寫法但是零值概念啊等等一些設(shè)計(jì),在加上在panic的時(shí)候還可以使用recover進(jìn)行處理,我覺得還是可以接受的。
在進(jìn)入正題之前我們還是需要新了解一下panic和recover和error
golang新手特別喜歡將panic當(dāng)作exception(我也是這么過來(lái)的。。),而這么做會(huì)導(dǎo)致panic被濫用。
func recover() interface{}
recover 是一個(gè)內(nèi)建的函數(shù),用于重新獲得 panic 協(xié)程的控制。 只有在延遲函數(shù)的內(nèi)部,調(diào)用 recover 才有用。在延遲函數(shù)內(nèi)調(diào)用 recover,可以取到 panic 的錯(cuò)誤信息,并且停止 panic 續(xù)發(fā)事件(Panicking Sequence),程序運(yùn)行恢復(fù)正常。如果在延遲函數(shù)的外部調(diào)用 recover,就不能停止 panic 續(xù)發(fā)事件。
golang中內(nèi)置的錯(cuò)誤類型error是一個(gè)接口,自定義的錯(cuò)誤類型必須實(shí)現(xiàn)error接口,這樣調(diào)用可以通過Error()獲取到具體的錯(cuò)誤信息而不用關(guān)系錯(cuò)誤的具體類型。
// The error built-in interface type is the conventional interface for // representing an error condition, with the nil value representing no error. type error interface { Error() string }
很多語(yǔ)言限制函數(shù)只能有一個(gè)返回值,這就顯得尤為寶貴,而golang的多返回值語(yǔ)法糖避免了這種方式帶來(lái)的不便,錯(cuò)誤值一般作為返回值列表的最后一個(gè),其他返回值是成功執(zhí)行時(shí)需要返回的信息。也就衍生出了如下判斷:
if err != nil { // error handling } else { // normal code }
雖然這種錯(cuò)誤處理方式代碼寫起來(lái)很蛋疼,但是golang風(fēng)格確實(shí)推薦使用此種方式。
var numIsZero = errors.New("num1 is zero") var numIsNotZero = errors.New("num1 is not zero") func GetInt(num1 int) (int, error) { if num1 == 0 { return num1, numIsZero } else { return num1, numIsNotZero } } //比較錯(cuò)誤 func ErrEquals() { _, err := GetInt(1) if err == numIsNotZero { } }
HTTP 表示客戶端的錯(cuò)誤狀態(tài)碼有幾十個(gè)。如果為每種狀態(tài)碼都預(yù)定義相應(yīng)的錯(cuò)誤值,代碼會(huì)變得很繁瑣:
var ErrBadRequest = errors.New("status code 400: bad request") var ErrUnauthorized = errors.New("status code 401: unauthorized")
這種場(chǎng)景下最佳的最法是自定義一種錯(cuò)誤類型,并且至少實(shí)現(xiàn) Error() 方法(滿足 error 定義):
type HTTPError struct { Code int Description string } func (h *HTTPError) Error() string { return fmt.Sprintf("status code %d: %s", h.Code, h.Description) }
這種方式下進(jìn)行等值判斷時(shí)需要轉(zhuǎn)成具體的自定義類型然后取出 Code 字段判斷:
func request() error { return HTTPError{404, "not found"} } func main() { err := request() if err != nil { // an error occured if err.(*HTTPError).Code == 404 { // handle a "not found" error } else { // handle a different error } } }
tyr catch 需要謹(jǐn)慎使用,因?yàn)閜anic / recover 和 try / catch 機(jī)制最大的不同在于控制流程上的區(qū)別。try / catch 機(jī)制控制流作用在 try 代碼塊內(nèi),代碼塊執(zhí)行到異常拋出點(diǎn)(throw)時(shí),控制流跳出 try 代碼塊,轉(zhuǎn)到對(duì)應(yīng)的 catch 代碼塊,然后繼續(xù)往下執(zhí)行。panic / recover 機(jī)制控制流則作用在整個(gè) goroutine 的調(diào)用棧。當(dāng) goroutine 執(zhí)行到 panic 時(shí),控制流開始在當(dāng)前 goroutine 的調(diào)用棧內(nèi)向上回溯(unwind)并執(zhí)行每個(gè)函數(shù)的 defer 。如果 defer 中遇到 recover 則回溯停止,如果執(zhí)行到 goroutine 最頂層的 defer 還沒有 recover ,運(yùn)行時(shí)就輸出調(diào)用棧信息然后退出。所以如果要使用 recover 避免 panic 導(dǎo)致進(jìn)程掛掉,recover 必須要放到 defer 里。為了避免過于復(fù)雜的代碼,最好不要使用嵌套的 defer ,并且 recover 應(yīng)該直接放到 defer 函數(shù)里直接調(diào)用。
package main import ( "fmt" ) func main() { defer func() { if err := recover(); err != nil { fmt.Println("error:", err) } }() fmt.Println("start") panic("Big Error") fmt.Println("stop") }
輸出:
start
error: Big Error
此部分的代碼相當(dāng)于try部分的代碼一旦被panic 后面的代碼就不會(huì)被執(zhí)行了,而是跳到 defer部分
fmt.Println("start") panic("Big Error") fmt.Println("stop")
接收到錯(cuò)誤并處理相當(dāng)于catch:
defer func() { if err := recover(); err != nil { fmt.Println("error:", err) } }()
注意如果想再次catch需要按照從下往上的循序進(jìn)行異常處理,原因的話了解defer。:
func main() { defer func() { if err := recover(); err != nil { fmt.Println("error:", err) } }() defer func() { if err := recover(); err != nil { fmt.Println("再次panic") panic(err) } }() fmt.Println("start") panic("Big Error") fmt.Println("stop") } func main() { defer func() { if err := recover(); err != nil { fmt.Println("error:", err) } }() defer func() { if err := recover(); err != nil { fmt.Println("再次panic") panic(err) } }() defer func() { if err := recover(); err != nil { fmt.Println("再次panic") panic(err) } }() defer func() { if err := recover(); err != nil { fmt.Println("再次panic") panic(err) } }() fmt.Println("start") panic("Big Error") fmt.Println("stop") }
輸出:
start
再次panic
再次panic
再次panic
error: Big Error
到此這篇關(guān)于Golang try catch與錯(cuò)誤處理的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Golang try catch與錯(cuò)誤處理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
標(biāo)簽:江西 武漢 張掖 宜賓 黑龍江 新余 延邊 嘉峪關(guān)
巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《Golang try catch與錯(cuò)誤處理的實(shí)現(xiàn)》,本文關(guān)鍵詞 Golang,try,catch,與,錯(cuò)誤,處理,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。