網站首頁 編程語言 正文
前言
上文我們了解了 Error
在 Go 中的設計理念。單從理念上來看, Error
的設計似乎有利于邏輯處理。但實際上,在開發(fā)過程中,我們還會遇到各種各樣的困難。為了優(yōu)化開發(fā)的流程,開發(fā)者們發(fā)明了很多處理 Error
的做法。今天我們就來看看目前 Go 開發(fā)中常見的幾大 Error
類型。
透明錯誤處理策略
在最簡單的 Go Error
設計中,開發(fā)者被期望通過判定函數(shù)返回的 err 值來確定調用是否正常。
value, err := doSomething() if err != nil { // 錯誤處理 } // 邏輯操作
這是 Go 語言中最常見的錯誤處理策略 ,80%以上的 Go 錯誤處理情形都可以歸類到這種策略下。這樣構造出的錯誤值代表的上下文信息,對錯誤處理方是透明的,因此這種策略稱為 透明錯誤處理策略 。
這種策略最大的問題是,無法判定錯誤的原因和種類。它只是簡單地把”是否出錯“分為了兩路邏輯。一旦我們的業(yè)務要求我們針對不同的錯誤原因,做不同的處理,這種情況就行不通了。
帶來的問題
透明策略只解決了”是否出錯“的問題,但開發(fā)者無法知道錯誤的原因。如果想要得到錯誤的內容,需要主動解析error值,這也引出了下面要講的處理策略。
哨兵(Sentinel)錯誤處理策略
哨兵策略策略主要是解決透明錯誤處理策略精度不夠的情況,它可以讓開發(fā)者得到“是什么錯誤”,而不僅是”是否出錯“。實際上,它就是通過預定義錯誤類型,在錯誤處理時,判斷錯誤是否屬于預定義的類別,從而做出處理。
因此我們可以得到它最簡單的實現(xiàn):
value, err := doSomething() if err!=nil { // 通過err.Error()獲得錯誤信息 switch err.Error(){ case "bufio: negative count": //特點錯誤處理 return // 其他判斷 default: // 未知錯誤原因 return } }
但這顯然不是好的寫法,會導致很嚴重的耦合問題。Go 1.13 之后,我們可以用 error.Is 方法很好地解決這個問題。
// 定義錯誤類型,一般變量用Err開頭 var( ErrInvalidUnreadByte=errors.New("bufio: invalid use of UnreadByte")ErrInvalidUnreadRune=errors.New("bufio: invalid use of UnreadRune") ErrBufferFull=errors.New("bufio: buffer full") ErrNegativeCount=errors.New("bufio: negative count") ) func main(){ value, err := doSomething() if errors.Is(err,ErrBufferFull){ //判斷是否為某類型錯誤 } }
帶來的問題
雖然哨兵策略解決了我們不能獲得錯誤原因的問題,但它本身也存在著設計缺陷。
1.對errors.Error()的依賴
==
的判斷依賴著 errors.Error()
的輸出。這是哨兵策略最大的問題。他導致了 error 值的擴展性很差,假如開發(fā)者想要為 error 帶上上下文或者錯誤行號,文件位置等信息,都會破壞哨兵策略的判斷。
從某種角度來看,errors.Error()
的輸出更應該是用于開發(fā)者的調試使用,而不應該作為程序判斷機制的一部分。
2.定義的錯誤類型會被公開
很多時候為了做錯誤類型判斷,一些包內需要定義許多錯誤類型。而這些錯誤類型通常會被共用,這使得他們不得不被公開。在公共庫中,被公開的錯誤類型必須有專門的文檔說明,否則會對使用者造成困惑。這會額外增加開發(fā)者的工作量。
再者,有時為了判斷某個特殊錯誤類型,使用者會引入對應的包。假如這種情況大量存在,會導致整個庫生態(tài)極其混亂。
Error types
Error types 是實現(xiàn)了 errors 接口的自定義類型,目的是為了更加具體地描述錯誤。開發(fā)者可以在類型上帶上需要的信息,如行號,文件位置等。可以參考下方:
type MyError struct { Msg string // 錯誤信息 Line int // 行號 FIle string // 文件位置 } // 實現(xiàn) errors 接口 func (e *MyError) Error()string{ return fmt.Sprintf("%s:%d: %s",e.File,e.Line,e.Msg) }
上面提到,修改 error 值會導致哨兵策略的失效, Error types 就是例子之一。由于是自定義的類型,我們不能再用 ==
判斷錯誤類型了,而是改用斷言。
value, ok := x.(MyError) if ok { //判斷是否為某類型錯誤 }
帶來的問題
可以看到 Error Types 最大的優(yōu)勢是其豐富的錯誤描述能力。但它仍然沒有解決哨兵策略下的問題。
不透明錯誤處理策略(Opaque errors)
不透明錯誤處理策略可以說是最靈活的處理方式,它要求代碼與調用者之間的耦合最少。開發(fā)者可以知道”是否出錯“,但無法得到錯誤的內部信息。
value, err := doSomething() if err != nil { // 錯誤處理 } // 邏輯操作
是的,在使用上不透明策略跟透明策略是很相似的。其中最大的不同是,透明策略可以通過 error.Error()
接口獲得錯誤信息。而不透明策略中是不可以的。
那如果開發(fā)者需要判斷錯誤類型怎么辦呢?不透明策略更推薦的是斷言 error 實現(xiàn)的行為,而不是特定的類型或值。可以參考下方代碼:
type temporary interface { Temporary() bool } // 封裝判斷函數(shù) func IsTemporary(err error) bool { // 斷言 te, ok := err.(temporay) // 是否滿足條件 return ok && te.Temporary() }
帶來的問題
不透明策略跟透明策略一樣,是很靈活的策略。他們的區(qū)別只在于錯誤的信息是否開放。因此,不透明策略依舊存在信息量缺乏的問題。
總結
今天我們了解了目前 Go 開發(fā)中常見的四種 Error 類型。這些類型各有優(yōu)劣,需要開發(fā)者在實際開發(fā)者中深入思考,做出取舍。通常我們需要考慮,我們開發(fā)的是工具還是業(yè)務,我們需要錯誤為我們提供靈活度還是精確的信息。掌握本文的內容,可以讓你在遇到錯誤處理時,有更多的處理思路。
當然,每種方式又會有問題,在接下來的文章里,我會分享一些常見的錯誤處理操作。
原文鏈接:https://juejin.cn/post/7174283953065426958
相關推薦
- 2022-05-19 C#?漢字與拼音互轉的實現(xiàn)示例_C#教程
- 2022-12-06 詳解Python的整數(shù)是如何實現(xiàn)的_python
- 2023-07-13 遍歷對象并改變對象某個屬性的值
- 2022-05-14 Python實現(xiàn)簡單的圖書管理系統(tǒng)_python
- 2023-11-22 Linux fatal: unable to access ‘https://github xxxx
- 2022-04-11 解決git push 錯誤error: src refspec master does not ma
- 2022-08-10 WPF中圖像處理的方法介紹_C#教程
- 2022-12-04 pyecharts如何旋轉折線圖的X軸標簽_python
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細win安裝深度學習環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結構-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支