Golang實踐之Error創(chuàng)建和處理詳解
error 基本概念
type error interface{
Error() string
}Golang 中 error類型是一個具有單個方法的接口,其內置方法是返回描述錯誤的字符串。Go 語言創(chuàng)始人覺得異常機制會導致控制流程混亂,降低代碼的可讀性,所以期望異常是一種可預知的。所以在使用時應當適當的返回 error ,然后調用方就可以更明確知道錯誤,進而再處理異常。同樣也說明了開發(fā)人員在 coding 時要能識別和預測可能發(fā)生錯誤,再進行處理,而不是忽略錯誤,
panic 和 recover
但可能也會出現一些我們無法預料的錯誤情況。比較嚴重的程序錯誤導致發(fā)生 panic 就會使程序結束,所以它又提供一個 recover 來捕獲 panic ,以便發(fā)生panic時能夠重新執(zhí)行啟動程序。
defer func() {
if r := recover(); r != nil {
fmt.Println("重新啟動程序:", r)
}
}()recover 函數最好在主函數中且必須在 defer 語句總使用,為了保證發(fā)生 panic 時被調用,如果沒有panic時recover 函數將會返回 nil。
對于panic 的錯誤,應當全面記錄錯誤信息,這樣才有利于排查問題。對于一些比較重要的服務應當適當增加報警機制以通知相關團隊或人員。
創(chuàng)建錯誤
// 方式1:使用 fmt.Errorof("")
func div(x, y int)(int,error){
if y==0 {
return 0,fmt.Errorof("除數 %d 不能為0",y)
}
return x/y, nil
}
// 方式2: 使用errors.New("")
ErrDivByZero := errors.New("除數不能為0")
return 0,ErrDivByZero
// 方式3:使用 errors.Wrap(err, "除數不能為0")
return 0,errors.Wrap(err, "除數不能為0")方式1中 fmt.Errorf 函數允許使用格式化字符串創(chuàng)建新錯誤。
errors.Wrap 函數允許使用上下文包裝error,使用場景:當函數調用另一個方法時遇到的錯誤而導致無法完成業(yè)務流程,那可能需要從函數返回錯誤。使用 errors.Wrap 函數需要注意:因其除了錯誤信息外還附加了堆棧信息,所以不能在程序中大量使用。
以上3種可以很簡單方便的創(chuàng)建錯誤。當然支持自定義錯誤類型,通過創(chuàng)建實現 error 接口的新類型。例如:
// 方式4: 自定義錯誤類型
type MathCalError struct {
message string
}
// 實現 Error 方法
func (e *MathCalError) Error() string {
return e.message
}
func div(x, y int) (int, error) {
if y == 0 {
return 0, &MathCalError{"除數不能為 0"}
}
return x / y, nil
}處理錯誤
根據遇到到場景,基本對于錯誤的處理大致有下面五種情況:
- 忽略錯誤:調用方對于發(fā)生錯誤覺得沒有任何影響,那么可以不接收直接忽略
- 記錄錯誤并繼續(xù)執(zhí)行:調用方覺得錯誤無影響但需要進行記錄,可以接受記錄
- 傳遞錯誤:繼續(xù)傳遞錯誤。
- 錯誤重試:某功能錯誤需要再重試,如請求第三方接口超時時想再重試。設置重試次數限制,以防止錯誤持續(xù)存在時出現無限循環(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("不合法參數")
// main 函數中使用
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)
}
}最后
有效的錯誤處理對于構建可靠的服務至關重要,個人覺得最佳的實踐是團隊內部的統(tǒng)一規(guī)范。沒有最佳實踐和方案,只有最適合的你的場景的實踐。
以上就是Golang實踐之Error創(chuàng)建和處理詳解的詳細內容,更多關于Golang Error創(chuàng)建和處理的資料請關注腳本之家其它相關文章!
相關文章
Go Excelize API源碼解讀GetSheetViewOptions與SetPageLayo
這篇文章主要為大家介紹了Go Excelize API源碼解讀GetSheetViewOptions與SetPageLayout方法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-08-08

