国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

先睹為快,Go2 Error 的掙扎之路

開發 后端
自從 Go 語言在國內火熱以來,除去泛型,其次最具槽點的就是 Go 對錯誤的處理方式,一句經典的 if err != nil 暗號就能認出你是一個 Go 語言愛好者。

 [[356198]]

本文轉載自微信公眾號「腦子進煎魚了」,作者陳煎魚 。轉載本文請聯系腦子進煎魚了公眾號。   

大家好,我是煎魚。

自從 Go 語言在國內火熱以來,除去泛型,其次最具槽點的就是 Go 對錯誤的處理方式,一句經典的 if err != nil 暗號就能認出你是一個 Go 語言愛好者。

自然,大家對 Go error 的關注度更是高漲,Go team 也是,因此在 Go 2 Draft Designs 中正式提到了 error handling(錯誤處理)的相關草案,希望能夠在未來正式的解決這個問題。

在今天這篇文章中,我們將一同跟蹤 Go2 error,看看他是怎么 “掙扎” 的,能不能破局?

為什么要吐槽 Go1

要吐槽 Go1 error,就得先知道為什么大家到底是在噴 Error 哪里處理的不好。在 Go 語言中,error 其實本質上只是個 Error 的 interface:

  1. type error interface { 
  2.     Error() string 

實際的應用場景如下:

  1. func main() { 
  2.  x, err := foo() 
  3.  if err != nil { 
  4.    // handle error 
  5.  } 

單純的看這個例子似乎沒什么問題,但工程大了后呢?

顯然 if err != nil 的邏輯是會堆積在工程代碼中,Go 代碼里的 if err != nil 甚至會達到工程代碼量的 30% 以上:

  1. func main() { 
  2.  x, err := foo() 
  3.  if err != nil { 
  4.    // handle error 
  5.  } 
  6.  y, err := foo() 
  7.  if err != nil { 
  8.    // handle error 
  9.  } 
  10.  z, err := foo() 
  11.  if err != nil { 
  12.    // handle error 
  13.  } 
  14.  s, err := foo() 
  15.  if err != nil { 
  16.    // handle error 
  17.  } 

暴力的對比一下,就發現四行函數調用,十二行錯誤,還要苦練且精通 IDE 的快速折疊功能,還是比較麻煩的。

另外既然是錯誤處理,那肯定不單單是一個 return err 了。在工程實踐中,項目代碼都是層層嵌套的,如果直接寫成:

  1. if err != nil { 
  2.  return err 

在實際工程中肯定是不行。你怎么知道具體是哪里拋出來的錯誤信息,實際出錯時只能瞎猜。大家又想出了 PlanB,那就是加各種描述信息:

  1. if err != nil { 
  2.  logger.Errorf("煎魚報錯 err:%v", err) 
  3.  return err 

雖然看上去人模人樣的,在實際出錯時,也會遇到新的問題,因為你要去查這個錯誤是從哪里拋出來的,沒有調用堆棧,單純幾句錯誤描述是難以定位的。

這時候就會發展成到處打錯誤日志:

  1. func main() { 
  2.  err := bar() 
  3.  if err != nil { 
  4.   logger.Errorf("bar err:%v", err) 
  5.  } 
  6.  ... 
  7.  
  8. func bar() error { 
  9.  _, err := foo() 
  10.  if err != nil { 
  11.   logger.Errorf("foo err:%v", err) 
  12.   return err 
  13.  } 
  14.  
  15.  return nil 
  16.  
  17. func foo() ([]byte, error) { 
  18.  s, err := json.Marshal("hello world."
  19.  if err != nil { 
  20.   logger.Errorf("json.Marshal err:%v", err) 
  21.   return nil, err 
  22.  } 
  23.  
  24.  return s, nil 

雖然到處打了日志,就會變成錯誤日志非常多,一旦出問題,人肉可能短時間內識別不出來。

最常見的就是到 IDE 上 ctrl + f 搜索是在哪出錯。同時在實際應用中我們會自定義一些錯誤類型,在 Go 則需要各種判斷和處理:

  1. if err := dec.Decode(&val); err != nil { 
  2.     if serr, ok := err.(*json.SyntaxError); ok { 
  3.        ... 
  4.     } 
  5.     return err 

你得判斷不等于 nil,還得對自定義的錯誤類型進行斷言,整體來講比較繁瑣。

匯總來講,Go1 錯誤處理的問題至少有:

  • 在工程實踐中,if err != nil 寫的煩,代碼中一大堆錯誤處理的判斷,占了相當的比例,不夠優雅。
  • 在排查問題時,Go 的 err 并沒有其他堆棧信息,只能自己增加描述信息,層層疊加,打一大堆日志,排查很麻煩。
  • 在驗證和測試錯誤時,要自定義錯誤(各種判斷和斷言)或者被迫用字符串校驗。

Go1.13 的挽尊

在 2019 年 09 月,Go1.13 正式發布。其中兩個比較大的兩個關注點分別是包依賴管理 Go modules 的轉正,以及錯誤處理 errors 標準庫的改進:

Error wrapping

在本次改進中,errors 標準庫引入了 Wrapping Error 的概念,并增加了 Is/As/Unwarp 三個方法,用于對所返回的錯誤進行二次處理和識別。

同時也是將 Go2 error 預規劃中沒有破壞 Go1 兼容性的相關功能提前實現了。

簡單來講,Go1.13 后 Go 的 error 就可以嵌套了,并提供了三個配套的方法。例子:

  1. func main() { 
  2.  e := errors.New("腦子進煎魚了"
  3.  w := fmt.Errorf("快抓住:%w", e) 
  4.  fmt.Println(w) 
  5.  fmt.Println(errors.Unwrap(w)) 

輸出結果:

  1. $ go run main.go 
  2. 快抓住:腦子進煎魚了 
  3. 腦子進煎魚了 

在上述代碼中,變量 w 就是一個嵌套一層的 error。最外層是 “快抓住:”,此處調用 %w 意味著 Wrapping Error 的嵌套生成。因此最終輸出了 “快抓住:腦子進煎魚了”。

需要注意的是,Go 并沒有提供 Warp 方法,而是直接擴展了 fmt.Errorf 方法。而下方的輸出由于直接調用了 errors.Unwarp 方法,因此將 “取” 出一層嵌套,最終直接輸出 “腦子進煎魚了”。

對 Wrapping Error 有了基本理解后,我們簡單介紹一下三個配套方法:

  1. func Is(err, target error) bool 
  2. func As(err error, target interface{}) bool 
  3. func Unwrap(err error) error 

errors.Is

方法簽名:

  1. func Is(err, target error) bool 

方法例子:

  1. func main() { 
  2.  if _, err := os.Open("non-existing"); err != nil { 
  3.   if errors.Is(err, os.ErrNotExist) { 
  4.    fmt.Println("file does not exist"
  5.   } else { 
  6.    fmt.Println(err) 
  7.   } 
  8.  } 
  9.  

errors.Is 方法的作用是判斷所傳入的 err 和 target 是否同一類型,如果是則返回 true。

errors.As

方法簽名:

  1. func As(err error, target interface{}) bool 

方法例子:

  1. func main() { 
  2.  if _, err := os.Open("non-existing"); err != nil { 
  3.   var pathError *os.PathError 
  4.   if errors.As(err, &pathError) { 
  5.    fmt.Println("Failed at path:", pathError.Path) 
  6.   } else { 
  7.    fmt.Println(err) 
  8.   } 
  9.  } 
  10.  

errors.As 方法的作用是從 err 錯誤鏈中識別和 target 相同的類型,如果可以賦值,則返回 true。

errors.Unwarp

方法簽名:

  1. func Unwrap(err error) error 

方法例子:

  1. func main() { 
  2.  e := errors.New("腦子進煎魚了"
  3.  w := fmt.Errorf("快抓住:%w", e) 
  4.  fmt.Println(w) 
  5.  fmt.Println(errors.Unwrap(w)) 

該方法的作用是將嵌套的 error 解析出來,若存在多級嵌套則需要調用多次 Unwarp 方法。

民間自救 pkg/errors

Go1 的 error 處理固然存在許多問題,因此在 Go1.13 前,早已有 “民間” 發現沒有上下文調試信息在實際工程應用中存在嚴重的體感問題。

因此 github.com/pkg/errors 在 2016 年誕生了,該庫也已經受到了極大的關注。

官方例子如下:

  1. type stackTracer interface { 
  2.     StackTrace() errors.StackTrace 
  3.  
  4. err, ok := errors.Cause(fn()).(stackTracer) 
  5. if !ok { 
  6.     panic("oops, err does not implement stackTracer"
  7.  
  8. st := err.StackTrace() 
  9. fmt.Printf("%+v", st[0:2]) // top two frames 
  10.  
  11. // Example output
  12. // github.com/pkg/errors_test.fn 
  13. // /home/dfc/src/github.com/pkg/errors/example_test.go:47 
  14. // github.com/pkg/errors_test.Example_stackTrace 
  15. // /home/dfc/src/github.com/pkg/errors/example_test.go:127 

簡單來講,就是對 Go1 error 的上下文處理進行了優化和處理,例如類型斷言、調用堆棧等。若有興趣的小伙伴可以自行到 github.com/pkg/errors 進行學習。

另外你可能會發現 Go1.13 新增的 Wrapping Error 體系與 pkg/errors 有些相像。

你并沒有體會錯,Go team 接納了相關的意見,對 Go1 進行了調整,但調用堆棧這塊因綜合原因暫時沒有納入。

Go2 error 要解決什么問題

在前面我們聊了 Go1 error 的許多問題,以及 Go1.13 和 pkg/errors 的自救和融合。你可能會疑惑,那...Go2 error 還有出場的機會嗎?即使 Go1 做了這些事情,Go1 error 還有問題嗎?

并沒有解決,if err != nil 依舊一把梭,目前社區聲音依然認為 Go 語言的錯誤處理要改進。

Go2 error proposal

在 2018 年 8 月,官方正式公布了 Go 2 Draft Designs,其中包含泛型和錯誤處理機制改進的初步草案:

Go2 Draft Designs

注:Go1.13 正式將一些不破壞 Go1 兼容性的 Error 特性加入到了 main branch,也就是前面提到的 Wrapping Error。

錯誤處理(Error Handling)

第一個要解決的問題就是大量 if err != nil 的問題,針對此提出了 Go2 error handling 的草案設計。

簡單例子:

  1. if err != nil { 
  2.  return err 

優化后的方案如下:

  1. func CopyFile(src, dst string) error { 
  2.  handle err { 
  3.   return fmt.Errorf("copy %s %s: %v", src, dst, err) 
  4.  } 
  5.  
  6.  r := check os.Open(src) 
  7.  defer r.Close() 
  8.  
  9.  w := check os.Create(dst) 
  10.  handle err { 
  11.   w.Close() 
  12.   os.Remove(dst) // (only if a check fails) 
  13.  } 
  14.  
  15.  check io.Copy(w, r) 
  16.  check w.Close() 
  17.  return nil 

主函數:

  1. func main() { 
  2.  handle err { 
  3.   log.Fatal(err) 
  4.  } 
  5.  
  6.  hex := check ioutil.ReadAll(os.Stdin) 
  7.  data := check parseHexdump(string(hex)) 
  8.  os.Stdout.Write(data) 

該提案引入了兩種新的語法形式,首先是 check 關鍵字,其可以選中一個表達式 check f(x, y, z) 或 check err,其將會標識這是一個顯式的錯誤檢查。

其次引入了 handle 關鍵字,用于定義錯誤處理程序流轉,逐級上拋,依此類推,直到處理程序執行 return 語句,才正式結束。

錯誤值打印(Error Printing)

第二個要解決的問題是錯誤值(Error Values)、錯誤檢查(Error Inspection)的問題,其引申出錯誤值打印(Error Printing)的問題,也可以認為是錯誤格式化的不便利。

官方針對此提出了提出了 Error Values 和 Error Printing 的草案設計。

簡單例子如下:

  1. if err != nil { 
  2.  return fmt.Errorf("write users database: %v", err) 

優化后的方案如下:

  1. package errors 
  2.  
  3. type Wrapper interface { 
  4.  Unwrap() error 
  5.  
  6. func Is(err, target error) bool 
  7. func As(type E)(err error) (e E, ok bool) 

該提案增加了錯誤鏈的 Wrapping Error 概念,并同時增加 errors.Is 和 errors.As 的方法,與前面說到的 Go1.13 的改進一致,不再贅述。

需要留意的是,Go1.13 并沒有實現 %+v 輸出調用堆棧的需求,因為此舉會破壞 Go1 兼容性和產生一些性能問題,大概會在 Go2 加入。

try-catch 不香嗎

社區中另外一股聲音就是直指 Go 語言反人類不用 try-catch 的機制,在社區內也產生了大量的探討,具體可以看看相關的提案 Proposal: A built-in Go error check function, "try"。

目前該提案已被拒絕,具體可參見 go/issues/32437#issuecomment-512035919 和 Why does Go not have exceptions。

總結

在這篇文章中,我們介紹了目前 Go1 Error 的現狀,概括了大家對 Go 語言錯誤處理的常見問題和意見。

同時還介紹了在這幾年間,Go team 針對 Go2、Go1.13 Error 的持續優化和探索。

 

責任編輯:武曉燕 來源: 腦子進煎魚了
相關推薦

2014-09-01 10:22:29

Ubuntu

2009-11-20 09:11:07

Chrome OS谷歌操作系統

2012-09-21 10:49:16

虛擬化

2019-12-26 12:00:24

ECUG Con 20

2011-03-09 10:45:09

DiscuzX2公測新功能

2010-10-20 08:53:57

Android 3.0

2009-02-20 08:51:22

.NET框架CLR組件

2015-07-30 10:05:37

Java9JShell

2013-03-25 09:51:53

Facebook數據中心云數據中心

2015-05-12 11:49:45

OpenStack K開源特性分析

2011-11-30 08:41:20

NoSQL數據庫

2009-03-31 09:04:46

MacChrome瀏覽器

2021-06-17 08:00:00

Windows 10Windows微軟

2009-10-28 12:27:36

linux操作系統發展

2011-04-08 16:14:21

2015-04-23 10:57:07

Apple WatchAPP

2011-04-01 11:26:21

JDK 7

2010-11-17 11:25:20

高交會郵件安全263企業郵箱

2009-02-12 15:18:59

2009-12-21 13:28:00

英特爾32納米
點贊
收藏

51CTO技術棧公眾號

国产福利视频在线观看| 日韩黄色三级| 亚洲综合在线第一页| 国产一级不卡视频| 亚洲欧美日韩视频二区| 91精品视频在线| 精品国产一区二区三区久久久樱花| 亚洲精品电影网在线观看| 国产福利在线免费观看| 一区二区三区中文字幕电影| 男人揉女人奶房视频60分| 91在线一区二区三区| 日韩欧美精品在线不卡| 欧美日本亚洲韩国国产| 91影视免费在线观看| 久久久久久美女精品| 精品电影一区二区三区| 国产无套粉嫩白浆在线2022年| 亚洲色图在线看| 中日韩午夜理伦电影免费| 欧美激情免费观看| av高清资源| 国产成人日日夜夜| 亚洲高清福利| 日韩av手机在线观看| 美女视频网站黄色亚洲| 久久精品中文字幕一区二区三区 | 精品影院一区| 欧美性生交大片免网| 米奇777四色精品人人爽| 久久精品美女视频网站| 国产区视频在线| 日韩欧美黄色影院| 91精品啪在线观看国产18| 白白操在线视频| 日韩在线观看av| 成人教育av在线| 国内久久久精品| 视频一区二区中文字幕| 黄色片在线免费看| 7777精品久久久大香线蕉小说| 亚洲成人久久影院| 天堂综合网久久| 免费观看羞羞视频网站| 茄子视频成人在线| 亚洲午夜久久久久中文字幕久| 国产成人调教视频在线观看| 美女黄视频在线播放 | 欧美性孕妇孕交| 亚洲精品久久视频| 亚洲专区一区| 夜色资源站国产www在线视频| 成人午夜一级二级三级| 欧美嫩在线观看| а√天堂8资源在线| 欧美国产日韩中文字幕在线| 91精彩视频在线观看| 亚洲欧美国产一本综合首页| 亚洲+小说+欧美+激情+另类| 婷婷五月色综合| 亚洲色图在线看| 成人免费影院| 91亚洲va在线va天堂va国| 不卡电影一区二区三区| 成年人视频在线免费观看| 欧美第一黄色网| 日本视频在线一区| 午夜爽爽视频| 亚洲天堂视频在线观看| 综合在线视频| 欧洲av无码放荡人妇网站| 欧洲一区二区三区免费视频| 91麻豆精品国产91久久久久推荐资源| 欧美精品七区| 夜夜精品浪潮av一区二区三区| 看黄在线观看| 97神马电影| 国产精品护士白丝一区av| 91精品欧美一区二区三区综合在| 欧美军人男男激情gay| 久久久久久av无码免费网站下载| 国产精品久久三区| 97免费高清电视剧观看| 欧美a一区二区| 欧美成人xxxxx| 国产成人av影院| 日本在线视频1区| 欧美人与性动交| 日韩电影在线免费观看| 欧美一区二区少妇| 91高清视频在线免费观看| 成人永久免费视频| 毛片在线导航| 极品校花啪啪激情久久| 一区二区三区中文免费| 亚洲欧美综合久久久久久v动漫| 三区精品视频| 欧美日韩国产系列| 久久久久久免费视频| 电影天堂最新网址| 欧美理论片在线观看| 国产成人精品免费在线| 成人三级高清视频在线看| 精品久久蜜桃| 欧美图区在线视频| 1024精品久久久久久久久| 国产在线视频你懂| 欧美大片免费看| 91麻豆免费看| 国产精品久久久久77777丨| 亚洲一区三区视频在线观看| 欧美一卡2卡3卡4卡| 亚洲人成免费| 国产黄色免费在线观看| 91久久精品在线| 精品福利在线视频| 日韩欧美网址| 亚洲男男gay视频| 国产91在线高潮白浆在线观看 | 国产深夜精品福利| 亚洲欧洲国产专区| 久久精品色综合| 一女二男3p波多野结衣| 欧美激情18p| 中文字幕乱码亚洲精品一区| 狠狠一区二区三区| 欧美色老女人| 国产精品igao视频| 午夜精品爽啪视频| 欧美在线三区| 久操视频在线观看| 神马影院午夜我不卡| 亚洲男人av在线| 成人一级黄色片| 成人在线超碰| 可以看美女隐私的网站| 成人a免费视频| 欧美日韩一区二区三区在线| 在线亚洲免费| 三级中文字幕在线观看| 妞干网在线播放| 欧美成人激情视频| 一区二区三区在线影院| 欧美日韩第一区| 性欧美高清come| 欧美日韩不卡在线视频| 久久久日本电影| 一二三区精品视频| 国产精品videossex久久发布| dy888亚洲精品一区二区三区| 无码毛片aaa在线| 欧美精品videosex性欧美| 午夜精品久久一牛影视| 亚洲欧美视频一区二区三区| 小草在线视频免费播放| 国产免费成人在线| 国产精品一区二区久久精品 | 精品精品国产国产自在线| 国产日韩欧美精品一区| 我不卡影院28| 免费男女羞羞的视频网站在线观看| 成年人深夜视频| 久久久久久久久久久久久久久久久久av| 亚洲精品亚洲人成人网在线播放| 亚洲久久一区二区| 久久久加勒比| 性感av在线播放| 超碰人人爱人人| 国产精品尤物福利片在线观看| 日韩亚洲欧美在线观看| 久久久另类综合| 激情综合视频| 日本亚洲欧洲无免费码在线| 色综合久久网女同蕾丝边| 日本一区二区三区四区五区六区| 欧美国产中文字幕| 亚洲三级电影网站| 欧美一区二区免费观在线| 亚洲欧美国产高清va在线播| 欧美富婆性猛交| 国产日韩欧美亚洲一区| 日韩影视精品| av动漫在线观看| 婷婷成人激情| 精品影片在线观看的网站| 久久久久久久尹人综合网亚洲| 国产精品无码永久免费888| 亚洲乱码一区二区| 成人蜜桃视频| 国产三级精品网站| 一区二区三区国产精品| 免费亚洲网站| 日韩精品免费一区二区三区竹菊| 伦理片一区二区三区| 国产精品主播直播| 欧美成人四级hd版| 日韩中文字幕一区二区| 欧美激情乱人伦一区| 日韩免费在线观看| 亚洲欧美激情小说另类|