首頁 > 軟體

Go error的使用方式詳解

2022-05-30 14:01:45

概述

當我們需要在Go專案中設計error,就不得不先知道Go error幾種常用方法。標準庫是一個非常好的學習方式,除此之外Go1.13的errors特性也需要掌握。

error使用方式

1.直接判等

這裡的判等又分為變數判等和型別判等。
適用於pkg中預先定義好了多個error變數或型別,err只可能是這些變數的其中一個。
案例:os.IsExist(err)

// 變數判等
var errObj = errors.New(errObj)
func IsErrObj(err error) bool {
    return err == errObj
}
// 型別判等
type PathError struct {
   Op   string
   Path string
   Err  error
}
func IsPathError(err error) bool {
    switch e := err.(type) {
    case *PathError:
        return true
    default:
        return false
    }
} 

2.組合error介面,構建更強大的error介面

適用於構造pkg級別專用的error介面型別,同時在struct中組合Err變數表示底層錯誤
案例:net.Error interface

package net
type Error interface {
   error
   Timeout() bool   // Is the error a timeout?
   Temporary() bool // Is the error temporary?
}

type AddrError struct {
   Err  string
   Addr string
}

3.Errno模式

我們知道Linux有大量的錯誤碼,表示了各種錯誤型別,對於很多系統而言錯誤碼非常好用。Go如何相容這種errono模式呢?
案例:sysacall.Errno

type Errno uintptr
func (e Errno) Error() string {
   if 0 <= int(e) && int(e) < len(errors) {
      s := errors[e]
      if s != "" {
         return s
      }
   }
   return "errno " + itoa.Itoa(int(e))
}

4.Go1.13的Wrap模式

在一些場景下,error是有鏈式關係的,我們固然可以自己實現一種鏈式error型別,但是Go1.13引入了語言級別的支援。它非常簡單,只要3個重要的用法:

// 建立error
err2 := fmt.Errorf("%w", err1)
// 判斷error鏈條中是否包含某個err變數
ok := errors.Is(err2, err1) // true
// 判斷error鏈條中是否可賦值為某個err型別,成功則賦值給target
type Errno int
func (e *Errno) Error() string {
   return strconv.Itoa(int(*e))
}

func test() {
    var no = Errno(1)
    no1 := fmt.Errorf("%w", &no)
    no2 := fmt.Errorf("%w", no1)
    
    var target *Errno
    ok := errors.As(no2, target)
    fmt.Println(ok, target) // true, 1
}

以上程式碼都依賴 errors.Unwrap 函數,這個函數通過反射解析出鏈式error的上一個error。
從程式碼可以看出,error.Is 用於我們有2個err變數的情況下,判斷前者是否連結了後者;
error.As 用於我們有一個err變數和一種error型別,想要判斷鏈子中是否包含了這種error型別,如果是,我們順帶將值儲存在target中,相當於丟棄了一些鏈式的資訊,返璞歸真。 這裡有2個注意點:

  • Unwrap依賴反射,我們知道Go的反射是很慢的,所以需要考慮效能的場景慎用
  • As函數使用是,target本身必須是struct的指標型別,並且要取地址,否則可能會panic

5. Go版本低時的鏈式error

有時候我們會看到 github.com/pkg/errors 這個包,它其實就是老版本Go想要使用鏈式error所參照的包,它常用的方法是 Wrap 和 Cause,所以看到這2個函數就可以猜到一個專案沒有使用新的errors特性。

到此這篇關於Go error的使用方式選擇的文章就介紹到這了,更多相關Go error使用內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com