淺析go的error
go 中 errors 包的方法解釋:
New: 創(chuàng)建一個ErrorIs:判斷是不是特定的一個ErrorAs:類型轉(zhuǎn)換為特定的ErrorUnWrap: 解除包裝,返回被包裝的error.
error.New(string) 方法返回的是 error struct 的指針。
errors is values. error 其實(shí)就是一個interface (struct)
error的類型Sentinel Error
Sentinel Error 預(yù)定義的特定錯誤.我們稱為 Sentinel Error. 這個名字來源于計算機(jī)編程中使用一個特定值來表示不可能進(jìn)一步處理的錯誤。類似于:io.EOF 或者,更底層的:syscall.ENOENT.
盡可能避免的使用Sentinel Error
func?demo1()?{
?err?:=?errors.New("this?is?a?error")
?println(err.Error())
}
Error Type (錯誤類型)
Error Type 是實(shí)現(xiàn)了 error 接口的自定義類型。例如下面的MyError. 用戶可以使用斷言來轉(zhuǎn)換這個錯誤,獲取更多的異常信息。如 下代碼. 相比于 Sentinel Error, Error Type的一大改進(jìn)就是 能夠?yàn)榘b底層 error 提供上下文。例如os.PathError. 但是:調(diào)用使用類型斷言和類型 switch .就要讓自定義的 error 變?yōu)?public 。這種模型會導(dǎo)致錯誤類型和調(diào)用者強(qiáng)耦合,從而導(dǎo)致Api變得脆弱。
建議:避免使用 error Type 或者 至少避免將他們作為公共API的一部分。
//?MyError?/**?demo2.
type?MyError?struct?{
?msg????????string
?fileName???string
?lineNumber?int
}
//?實(shí)現(xiàn)了 error接口。
func?(m?*MyError)?Error()?string?{
?return?fmt.Sprintf("%s:%d:?%s",?m.fileName,?m.lineNumber,?m.msg)
}
func?testError()?error?{
?return?&MyError{msg:?"this?is?a?error",?fileName:?"demo8_error_resolve",?lineNumber:?50}
}
func?demo2()?{
?err?:=?testError()
?switch?err?:=?err.(type)?{
?case?nil:
?case?*MyError:
??fmt.Println("error:?",?err.lineNumber)
?default:
?}
}
Opaque Error
將這種風(fēng)格稱為 不透明錯誤. 雖然你知道發(fā)生了錯誤,但是您沒能力看到錯誤的內(nèi)部,作為調(diào)用者,關(guān)于操作的結(jié)果,您所知道的就是他成功或者失敗了 ==> 只返回錯誤,但不返回錯誤內(nèi)容。==> 同時返回錯誤的類型,而不是錯誤的類型。如下示例:
func?Write(w?io.Writer,?buf?[]byte)?error?{
?_,?err?:=?w.Write(buf)
?return?fmt.Errorf("這里發(fā)生了錯誤,%w\n",?err)
}
//?OpaqueError?/*****?demo3
type?OpaqueError?interface?{
?error
?IsTemporary()?bool?//?是否是臨時錯誤。
?IsTimeout()?bool???//?是否是超時
}
type?temporary?interface?{
?Temporary()?bool
}
//?判斷是否為Temporary?Error.
func?isTemporary(err?error)?bool?{
?te,?ok?:=?err.(temporary)
?return?ok?&&?te.Temporary()
}
Handing Error 處理異常- 一種處理
error的方式,編寫代碼技巧,讓代碼更易讀。 wrap Errors. 使用第三方庫。github.com/pkg/errors. go的1.13版本之后,可以使用:fmt.Errorf("%w",err). 和errors.Is(),errors.As(). 規(guī)范:- 如果是一個跨項目,多重復(fù)用的項目里,應(yīng)該直接返回
error, 而不是返回包裝后的error. - 如果函數(shù)/方法不打算處理錯誤,那么用足夠的上下文
wrap error并將其返回到調(diào)用堆棧中。 - 一旦確定函數(shù)/方法要處理錯誤,錯誤就不再是錯誤, 如果函數(shù)/方法仍然需要發(fā)出返回,則它不能返回錯誤值,它應(yīng)該只返回零(比如降級處理中, 你返回了 降級數(shù)據(jù),然后需要返回
nil.)
- 如果是一個跨項目,多重復(fù)用的項目里,應(yīng)該直接返回
go 2.x 的發(fā)展參考建議多看看, 可以把握一下 go 未來的發(fā)展方向
https://go.googlesource.com/proposal/+/master/design/29934-error-values.md
https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling.md
https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling-overview.md
最后期望與你一起遇見更好的自己
期望與你一起遇見更好的自己