亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Go 1.13中errors包的新變化示例解析

 更新時間:2023年12月20日 10:00:14   作者:晁岳攀(鳥窩) 鳥窩聊技術(shù)  
這篇文章主要為大家介紹了Go 1.13中errors包的新變化示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

Go 1.13 中 errors 包有了一些變化

這些變化是為了更好地支持 Go 的錯誤處理提案。Go 1.20 中也增加了一個新方法,這個新方法可以代替第三方的庫處理多個 error,這篇文章將介紹這些變化。

因為原來的 Go 的 errors 中的內(nèi)容非常的簡單,可能會導(dǎo)致大家輕視這個包,對于新的變化不是那么的關(guān)注。讓我們一一介紹這些新的方法。

Unwrap

如果一個 err 實現(xiàn)了Unwrap函數(shù),那么errors.Unwrap會返回這個 err 的unwrap方法的結(jié)果,否則返回 nil。 一般標(biāo)準(zhǔn)的 error 都沒有實現(xiàn)Unwrap方法,比如io.EOF, 但是也有一小部分的 error 實現(xiàn)了Unwrap方法,比如os.PathError,os.LinkError、os.SyscallErrornet.OpError、net.DNSConfigError等等。

比如下面的代碼:

 fmt.Println(errors.Unwrap(io.EOF)) // nil
 _, err := net.Dial("tcp", "invalid.address:80")
 fmt.Println(errors.Unwrap(err))

第一行因為io.EOF沒有Unwrap方法,所以輸出 nil。 net.Dial 失敗返回的 err 是*net.OpError,它實現(xiàn)了Unwrap方法,返回更底層的*net.DNSError,所以第二行輸出為lookup invalid.address: no such host。

最常用的,我們使用fmt.Errorf + %w包裝一個 error,比如下面的代碼:

 e1 := fmt.Errorf("e1: %w", io.EOF)
 e2 := fmt.Errorf("e2: %w + %w", e1, io.ErrClosedPipe)
 e3 := fmt.Errorf("e3: %w", e2)
 e4 := fmt.Errorf("e4: %w", e3)
 fmt.Println(errors.Unwrap(e4)) // e3: e2: e1: EOF + io: read/write on closed pipe

這段代碼逐層進行了包裝,最后的e4包含了所有的 error,我們可以通過errors.Unwrap逐層進行解包,直到最底層的 error。 fmt.Errorf 可以 1 一次包裝多個 error,比如上面的e2,它包含了e1io.ErrClosedPipe兩個 error。

我們常常在多層調(diào)用的時候,把最底層的 error 逐層包裝傳遞上去,這個時候我們可以使用fmt.Errorf + %w包裝 error。 在最高層處理 error 的時候,再逐層Unwrap解開 error,逐層處理。

Is

Is函數(shù)檢查 error 的樹中是否包含指定的目標(biāo) error。

啥是 error 的? 一個 error 的數(shù)包括它本身,以及通過Unwrap方法逐層解開的 error。 error 的Unwrap方法的返回值,可能是單個 error,也可能是是多個 error,在返回多個 error 的時候,會采用深度優(yōu)先的方式進行遍歷檢查,尋找目標(biāo) error。

怎么才算找到目標(biāo) error 呢?一種情況就是此 err 就是目標(biāo) error,這沒有什么好說的,第二種就是此 err 實現(xiàn)了Is(err)方法,把目標(biāo) err 扔進Is方法返回 true。

所以從功能上看Is函數(shù)其實叫做Has函數(shù)更貼切些。

下面是一個例子:

    e1 := fmt.Errorf("e1: %w", io.EOF)
    e2 := fmt.Errorf("e2: %w + %w", e1, io.ErrClosedPipe)
    e3 := fmt.Errorf("e3: %w", e2)
    e4 := fmt.Errorf("e4: %w", e3)
    fmt.Println(errors.Is(e4, io.EOF)) // true
    fmt.Println(errors.Is(e4, io.ErrClosedPipe)) // true
    fmt.Println(errors.Is(e4, io.ErrUnexpectedEOF)) // false

As

Is是遍歷 error 的數(shù),檢查是否包含目標(biāo) error。As是遍歷 error 的數(shù),檢查每一個 error,看看是否可以把從 error 賦值給目標(biāo)變量,如果是,則返回 true,并且目標(biāo)變量已賦值,否則返回 false。

下面這個例子,我們可以看到As的用法:

 if _, err := os.Open("non-existing"); err != nil {
  var pathError *fs.PathError
  if errors.As(err, &pathError) {
   fmt.Println("failed at path:", pathError.Path)
  } else {
   fmt.Println(err)
  }
 }

如果 os.Open 返回的 error 的樹中包含*fs.PathError,那么errors.As會把這個 error 賦值給pathError變量,并且返回 true,否則返回 false。 我們這個例子正好制造的就是文件不存在的 error,所以它會輸出:failed at path: non-existing

經(jīng)常常犯的一個錯誤就是我們使用一個error變量作為As的第二個參數(shù)。下面這個例子 tmp 就是 error 接口類型,所以 origin 可以直接賦值給 tmp,所以errors.As返回 true,并且 tmp 的值就是 origin 的值。

 var origin = fmt.Errorf("error: %w", io.EOF)
 var tmp = io.ErrClosedPipe
 if errors.As(origin, &tmp) {
  fmt.Println(tmp) // error: EOF
 }

As使用起來總是那么別別扭扭,每次總得聲明一個變量,然后把這個變量傳遞給As函數(shù),在 Go 支持泛型之后,As應(yīng)該可以簡化成如下的方式:

func As[T error](err error "T error") (T, bool)

但是,Go 不會修改這個導(dǎo)致不兼容的 API,所以我們只能繼續(xù)保留As函數(shù),增加一個新的函數(shù)是一個可行的方法,無論它叫做IsA、AsOf還是AsTarget或者其他。

如果你已經(jīng)掌握了 Go 的泛型,你可以自己實現(xiàn)一個As函數(shù),比如下面的代碼:

func AsA[T error](err error "T error") (T, bool) {
 var isErr T
 if errors.As(err, &isErr) {
  return isErr, true
 }
 var zero T
 return zero, false
}

寫段測試代碼,我們可以看到它的效果:

type MyError struct{}
func (*MyError) Error() string { return "MyError" }
func main() {
 var err error = fmt.Errorf("error: %w", &MyError{})
 m, ok := AsA[*MyError](err "*MyError") // MyError does not implement error (Error method has pointer receiver)
 fmt.Println(m, ok)
}

大家在#51945[1]討論了一段時間,又是無疾而終了。

Join

在我們的項目中,有時候需要處理多個 error,比如下面的代碼:

func (s *Server) Serve() error {
    var errs []error
    if err := s.init(); err != nil {
        errs = append(errs, err)
    }
    if err := s.start(); err != nil {
        errs = append(errs, err)
    }
    if err := s.stop(); err != nil {
        errs = append(errs, err)
    }
    if len(errs) > 0 {
        return fmt.Errorf("server error: %v", errs)
    }
    return nil
}

這段代碼中,我們需要處理三個 error,如果有一個 error 不為 nil,那么我們就返回 errs。 當(dāng)然,為了處理多個 errors 情況,先前,有很多的第三方庫可以供我們使用,比如

go.uber.org/multierr

github.com/hashicorp/go-multierror

github.com/cockroachdb/errors

但是現(xiàn)在,你不用再造輪子或者使用第三方庫了,因為 Go 1.20 中增加了errors.Join函數(shù),它可以把多個 error 合并成一個 error,比如下面的代碼:

 var e1 = io.EOF
 var e2 = io.ErrClosedPipe
 var e3 = io.ErrNoProgress
 var e4 = io.ErrShortBuffer
 _, e5 := net.Dial("tcp", "invalid.address:80")
 e6 := os.Remove("/path/to/nonexistent/file")
 var e = errors.Join(e1, e2)
 e = errors.Join(e, e3)
 e = errors.Join(e, e4)
 e = errors.Join(e, e5)
 e = errors.Join(e, e6)
 fmt.Println(e.Error())
    // 輸出如下,每一個err一行
    //
 // EOF
 // io: read/write on closed pipe
 // multiple Read calls return no data or error
 // short buffer
 // dial tcp: lookup invalid.address: no such host
 // remove /path/to/nonexistent/file: no such file or directory
 fmt.Println(errors.Unwrap(e)) // nil
 fmt.Println(errors.Is(e, e6)) //true
 fmt.Println(errors.Is(e, e3)) // true
 fmt.Println(errors.Is(e, e1)) // true

你可以使用Is判斷是否包含某個 error,或者使用As提取出目標(biāo) error。

參考資料

[1]

#51945: https://github.com/golang/go/issues/51945

以上就是Go 1.13中errors包的新變化示例解析的詳細(xì)內(nèi)容,更多關(guān)于Go1.13 errors包變化的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Go語言學(xué)習(xí)之將mp4通過rtmp推送流媒體服務(wù)的實現(xiàn)方法

    Go語言學(xué)習(xí)之將mp4通過rtmp推送流媒體服務(wù)的實現(xiàn)方法

    對音視頻一直是小白,決定沉下心來,好好研究一下音視頻知識,下面這篇文章主要給大家介紹了關(guān)于Go語言學(xué)習(xí)之將mp4通過rtmp推送流媒體服務(wù)的實現(xiàn)方法,需要的朋友可以參考下
    2022-12-12
  • Go之集合slice的實現(xiàn)

    Go之集合slice的實現(xiàn)

    本文主要介紹了Go之集合slice的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Golang安裝和使用protocol-buffer流程介紹

    Golang安裝和使用protocol-buffer流程介紹

    這篇文章主要介紹了Golang安裝和使用protocol-buffer過程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-09-09
  • 詳解如何在Go語言中生成隨機種子

    詳解如何在Go語言中生成隨機種子

    這篇文章主要為大家詳細(xì)介紹了如何在Go語言中生成隨機種子,文中的示例代碼講解詳細(xì),具有一定的借鑒價值,有需要的小伙伴可以參考一下
    2024-04-04
  • Go語言刪除文本文件中的指定行操作代碼

    Go語言刪除文本文件中的指定行操作代碼

    假設(shè)現(xiàn)在有一個文本文件,我們需要刪除文件中亂碼的行。我們可以使用go的os庫來處理文件,遍歷整個文件然后將除過亂碼的行寫入一個新文件,以此來實現(xiàn)我們的需求,這篇文章主要介紹了Go語言刪除文本文件中的指定行,需要的朋友可以參考下
    2023-12-12
  • Golang多線程刷票的實現(xiàn)代碼

    Golang多線程刷票的實現(xiàn)代碼

    這篇文章主要介紹了Golang多線程刷票的相關(guān)資料,這里實現(xiàn)刷票的功能,對于投票,刷票的很方便,并附實現(xiàn)代碼,需要的朋友可以參考下
    2017-07-07
  • Go語言常見錯誤之將接口定義在實現(xiàn)方

    Go語言常見錯誤之將接口定義在實現(xiàn)方

    在Go中,接口起到一個十分關(guān)鍵的角色,它們提供了一種方式來定義對象的行為,而不需要知道對象的具體實現(xiàn),一個常見的錯誤是在實現(xiàn)方而不是使用方定義接口,本文將詳細(xì)探討為何這樣做是一個錯誤,以及如何避免它
    2024-01-01
  • Go并發(fā):使用sync.WaitGroup實現(xiàn)協(xié)程同步方式

    Go并發(fā):使用sync.WaitGroup實現(xiàn)協(xié)程同步方式

    這篇文章主要介紹了Go并發(fā):使用sync.WaitGroup實現(xiàn)協(xié)程同步方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05
  • Go語言字符串操作指南:簡單易懂的實戰(zhàn)技巧

    Go語言字符串操作指南:簡單易懂的實戰(zhàn)技巧

    本文將介紹Go語言中字符串的實戰(zhàn)操作,通過本文的學(xué)習(xí),讀者將掌握Go語言中字符串的常用操作,為實際開發(fā)提供幫助,需要的朋友可以參考下
    2023-10-10
  • 解決老版本goland無法調(diào)試新版本go的問題

    解決老版本goland無法調(diào)試新版本go的問題

    這篇文章主要給大家介紹了如何解決老版本goland無法調(diào)試新版本go的問題,文中通過代碼示例給大家講解的非常詳細(xì),具有一定的參考價值,需要的朋友可以參考下
    2023-11-11

最新評論