Golang實踐之Error創(chuàng)建和處理詳解
error 基本概念
type error interface{ Error() string }
Golang 中 error類型是一個具有單個方法的接口,其內(nèi)置方法是返回描述錯誤的字符串。Go 語言創(chuàng)始人覺得異常機制會導致控制流程混亂,降低代碼的可讀性,所以期望異常是一種可預(yù)知的。所以在使用時應(yīng)當適當?shù)姆祷?error ,然后調(diào)用方就可以更明確知道錯誤,進而再處理異常。同樣也說明了開發(fā)人員在 coding 時要能識別和預(yù)測可能發(fā)生錯誤,再進行處理,而不是忽略錯誤,
panic 和 recover
但可能也會出現(xiàn)一些我們無法預(yù)料的錯誤情況。比較嚴重的程序錯誤導致發(fā)生 panic 就會使程序結(jié)束,所以它又提供一個 recover 來捕獲 panic ,以便發(fā)生panic時能夠重新執(zhí)行啟動程序。
defer func() { if r := recover(); r != nil { fmt.Println("重新啟動程序:", r) } }()
recover 函數(shù)最好在主函數(shù)中且必須在 defer 語句總使用,為了保證發(fā)生 panic 時被調(diào)用,如果沒有panic時recover 函數(shù)將會返回 nil。
對于panic 的錯誤,應(yīng)當全面記錄錯誤信息,這樣才有利于排查問題。對于一些比較重要的服務(wù)應(yīng)當適當增加報警機制以通知相關(guān)團隊或人員。
創(chuàng)建錯誤
// 方式1:使用 fmt.Errorof("") func div(x, y int)(int,error){ if y==0 { return 0,fmt.Errorof("除數(shù) %d 不能為0",y) } return x/y, nil } // 方式2: 使用errors.New("") ErrDivByZero := errors.New("除數(shù)不能為0") return 0,ErrDivByZero // 方式3:使用 errors.Wrap(err, "除數(shù)不能為0") return 0,errors.Wrap(err, "除數(shù)不能為0")
方式1中 fmt.Errorf 函數(shù)允許使用格式化字符串創(chuàng)建新錯誤。
errors.Wrap
函數(shù)允許使用上下文包裝error,使用場景:當函數(shù)調(diào)用另一個方法時遇到的錯誤而導致無法完成業(yè)務(wù)流程,那可能需要從函數(shù)返回錯誤。使用 errors.Wrap 函數(shù)需要注意:因其除了錯誤信息外還附加了堆棧信息,所以不能在程序中大量使用。
以上3種可以很簡單方便的創(chuàng)建錯誤。當然支持自定義錯誤類型,通過創(chuàng)建實現(xiàn) error 接口的新類型。例如:
// 方式4: 自定義錯誤類型 type MathCalError struct { message string } // 實現(xiàn) Error 方法 func (e *MathCalError) Error() string { return e.message } func div(x, y int) (int, error) { if y == 0 { return 0, &MathCalError{"除數(shù)不能為 0"} } return x / y, nil }
處理錯誤
根據(jù)遇到到場景,基本對于錯誤的處理大致有下面五種情況:
- 忽略錯誤:調(diào)用方對于發(fā)生錯誤覺得沒有任何影響,那么可以不接收直接忽略
- 記錄錯誤并繼續(xù)執(zhí)行:調(diào)用方覺得錯誤無影響但需要進行記錄,可以接受記錄
- 傳遞錯誤:繼續(xù)傳遞錯誤。
- 錯誤重試:某功能錯誤需要再重試,如請求第三方接口超時時想再重試。設(shè)置重試次數(shù)限制,以防止錯誤持續(xù)存在時出現(xiàn)無限循環(huán)。
- 嚴重錯誤終止程序:若有些錯誤期望終止程序,那直接 panic 處理。
// 忽略錯誤 result,_ := getUser() // 記錄錯誤 result,err := getUser();err!=nil{ log,writerInfo("something error", err.Error()) } // 傳遞錯誤 result,err := getUser();err!=nil{ return err } // 錯誤重試 retryCount := 0 maxRetryCount := 3 for { result,err := getUser(); if err!=nil{ return err if retryCount >= maxRetryCount{ return err } } select { case <-ctx.Done(): return ctx.Err() case <-time.After(time.Duration(retryCount) * time.Second): retryCount++ continue } } //錯誤后直接 panic if err := getUser(); err != nil { panic("something wrong") }
項目中使用 Error 的方案
方案一 :定義 ErrorMessage 包
項目中可以定義一個含有所有錯誤信息的包,然后在使用時直接引用。
package errorMsg import "errors" var UndefinedError = errors.New("未定義") var InvalidateParamsError = errors.New("不合法參數(shù)") // main 函數(shù)中使用 func getUser() error { return errorMsg.UndefinedError }
方案二:自定義 error 類型
type ParamNotFound NotFound type ValueNotFound NotFound type NotFound struct { msg string } func (n *NotFound) Error() string { return n.msg } // 通過使用 switch 處理不同類型的錯誤, func handleErrors(err error) { switch v := err.(type) { case ParamNotFound: fmt.Printf("ParamNotFound: %v\n", v) case ValueNotFound: fmt.Printf("ValueNotFound: %v\n", v) default: fmt.Printf("Other error: %v\n", v) } }
最后
有效的錯誤處理對于構(gòu)建可靠的服務(wù)至關(guān)重要,個人覺得最佳的實踐是團隊內(nèi)部的統(tǒng)一規(guī)范。沒有最佳實踐和方案,只有最適合的你的場景的實踐。
以上就是Golang實踐之Error創(chuàng)建和處理詳解的詳細內(nèi)容,更多關(guān)于Golang Error創(chuàng)建和處理的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
gtoken替換jwt實現(xiàn)sso登錄的問題小結(jié)
這篇文章主要介紹了gtoken替換jwt實現(xiàn)sso登錄,主要介紹了替換jwt的原因分析及gtoken的優(yōu)勢,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-05-05Go Excelize API源碼解讀GetSheetViewOptions與SetPageLayo
這篇文章主要為大家介紹了Go Excelize API源碼解讀GetSheetViewOptions與SetPageLayout方法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-08-08Golang中int類型和字符串類型相互轉(zhuǎn)換的實現(xiàn)方法
在日常開發(fā)中,經(jīng)常需要將數(shù)字轉(zhuǎn)換為字符串或者將字符串轉(zhuǎn)換為數(shù)字,在 Golang 中,有一些很簡便的方法可以實現(xiàn)這個功能,接下來就詳細講解一下如何實現(xiàn) int 類型和字符串類型之間的互相轉(zhuǎn)換,需要的朋友可以參考下2023-09-09