最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

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.LinkErroros.SyscallError、net.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

這段代碼逐層進(jìn)行了包裝,最后的e4包含了所有的 error,我們可以通過errors.Unwrap逐層進(jìn)行解包,直到最底層的 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)先的方式進(jìn)行遍歷檢查,尋找目標(biāo) error。

怎么才算找到目標(biāo) error 呢?一種情況就是此 err 就是目標(biāo) error,這沒有什么好說的,第二種就是此 err 實現(xiàn)了Is(err)方法,把目標(biāo) err 扔進(jìn)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實現(xiàn)凱撒密碼加密解密

    Go實現(xiàn)凱撒密碼加密解密

    這篇文章主要為大家介紹了Go實現(xiàn)凱撒密碼加密解密示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • Go語言ants協(xié)程池的具體使用

    Go語言ants協(xié)程池的具體使用

    ants是Go語言中一款高效的協(xié)程池庫,通過復(fù)用協(xié)程資源優(yōu)化高并發(fā)場景下的性能,本文就來介紹一下golang中大名鼎鼎的ants協(xié)程池庫的實現(xiàn)原理,感興趣的可以了解一下
    2025-08-08
  • Golang的strings.Split()踩坑記錄

    Golang的strings.Split()踩坑記錄

    工作中,當(dāng)我們需要對字符串按照某個字符串切分成字符串?dāng)?shù)組數(shù)時,常用到strings.Split(),本文主要介紹了Golang的strings.Split()踩坑記錄,感興趣的可以了解一下
    2022-05-05
  • Golang實現(xiàn)簡單http服務(wù)器的示例詳解

    Golang實現(xiàn)簡單http服務(wù)器的示例詳解

    這篇文章主要為大家詳細(xì)介紹了如何利用Golang實現(xiàn)簡單http服務(wù)器,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Golang有一定的幫助,需要的可以參考一下
    2023-03-03
  • 深入淺出Go語言:手把手教你高效生成與解析JSON數(shù)據(jù)

    深入淺出Go語言:手把手教你高效生成與解析JSON數(shù)據(jù)

    本文將帶你一步步走進(jìn)Go語言的世界,教你如何高效生成與解析JSON數(shù)據(jù),無論你是初學(xué)者還是經(jīng)驗豐富的開發(fā)者,都能在本文中找到實用的技巧和靈感,本文內(nèi)容簡潔明了,示例豐富,讓你在閱讀的過程中輕松掌握Go語言生成與解析JSON數(shù)據(jù)的技巧,需要的朋友可以參考下
    2024-02-02
  • Golang timer可能造成的內(nèi)存泄漏問題分析

    Golang timer可能造成的內(nèi)存泄漏問題分析

    本文探討了Golang中timer可能造成的內(nèi)存泄漏問題,通過分析一段代碼,解釋了為什么協(xié)程在調(diào)用timer.Stop()后無法正常退出,文章指出,timer.Stop()并不關(guān)閉Channel,導(dǎo)致協(xié)程無法繼續(xù)執(zhí)行,最后,提出了一種修復(fù)方法,并呼吁大家關(guān)注和分享
    2024-12-12
  • Go集成swagger實現(xiàn)在線接口文檔的教程指南

    Go集成swagger實現(xiàn)在線接口文檔的教程指南

    wagger是一個用于設(shè)計,構(gòu)建和文檔化API的開源框架,在Go語言中,Swagger可以幫助后端開發(fā)人員快速創(chuàng)建和定義RESTful API,并提供自動生成接口文檔的功能,所以本文給大家介紹了Go集成swagger實現(xiàn)在線接口文檔的方法,需要的朋友可以參考下
    2024-11-11
  • Go語言中io包核心接口示例詳解

    Go語言中io包核心接口示例詳解

    Go的io包提供了io.Reader和io.Writer接口,分別用于數(shù)據(jù)的輸入和輸出,下面這篇文章主要給大家介紹了關(guān)于Go語言中io包核心接口的相關(guān)資料,需要的朋友可以參考下
    2021-12-12
  • Go語言實現(xiàn)AzDG可逆加密算法實例

    Go語言實現(xiàn)AzDG可逆加密算法實例

    這篇文章主要介紹了Go語言實現(xiàn)AzDG可逆加密算法,實例分析了AzDG可逆加密算法的實現(xiàn)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-02-02
  • Golang設(shè)計模式之組合模式講解

    Golang設(shè)計模式之組合模式講解

    這篇文章主要介紹了Golang設(shè)計模式之組合模式,組合模式針對于特定場景,如文件管理、組織管理等,使用該模式能簡化管理,使代碼變得非常簡潔
    2023-01-01

最新評論

广平县| 上杭县| 甘泉县| 黎川县| 湖南省| 武隆县| 麻江县| 贞丰县| 和硕县| 徐水县| 洛南县| 武乡县| 龙里县| 荣昌县| 监利县| 石城县| 江北区| 佛教| 德格县| 阿合奇县| 闽侯县| 定州市| 铜鼓县| 句容市| 贺州市| 贵港市| 花垣县| 尼木县| 岗巴县| 文水县| 定安县| 甘孜县| 武平县| 尼玛县| 嵊泗县| 唐山市| 壤塘县| 广饶县| 青神县| 阳原县| 普陀区|