基礎
錯誤處理應該是工程的一部分,Golang中的error是一個interface
類型,如下:
type error interface { Error() string }
凡是實作Error()
方法的結構,都可以當作錯誤處理。因此如果函數可能出現錯誤,那麼可以在傳回值的最後,傳回一個錯誤,例如:
func foo() error { // ... do something return errors.New("foo error") }
#直接傳回錯誤
直接傳回錯誤,類似於直接傳回字串類型的錯誤,或錯誤碼之類的。字串類型的錯誤,在基礎部分提到了。錯誤碼相當於Linux、C程式中的錯誤碼,一般我們需要自己定義。舉個例子:
package mypkg type ErrCode int const ( ERR1 = 1 ERR2 = 2 ERR3 = 3 ) func sub(a, b int) (int, ErrCode) { if b < 0 { return 0, ERR1 } else if a < b { return 0, Err2 } else if a < 0 { return 0, Err3 } return a - b }
這種類型的錯誤,編寫簡單,但是有兩個缺陷:
1、外層如果想要使用錯誤碼,則需要引入這個包,容易出現循環引用的情況。
2、如果套件內部修改回傳的錯誤碼類型,則外部使用到錯誤碼的地方,都要進行對應的修改,破壞了封閉性。
對於第一個缺陷,可以使用一個第三方的包,專門存放錯誤碼,這個方式值得商榷。永遠不要透過判斷Error()方法傳回的字串的值,來進行對應的錯誤處理! ! !
傳回自訂類型的錯誤
該方式可以傳回自訂的類型,並透過斷言自訂類型,來進行相關的錯誤處理;自訂類型可以攜帶更多的信息,程式碼實例:
package main import ( "errors" "fmt" "runtime/debug" ) type MyError struct { Inner error // 内粗错误 Message string // 自定义错误信息 StackTrace string // 堆栈信息 Misc map[string]interface{} //其它的一些数据 } func (myError MyError) Error() string { return myError.Message } func wrapError(err error, msg string, msgArgs ...interface{}) MyError { return MyError{ Inner: err, Message: fmt.Sprintf(msg, msgArgs), StackTrace: string(debug.Stack()), Misc: make(map[string]interface{}), } } func Handle(key int) error { if key < 0 { return wrapError(errors.New("key < 0"), "This is an error test") } return nil } func main() { if err := Handle(-1); err != nil { if e, ok := err.(MyError); ok { fmt.Printf("Inner: %v, Message: %v, StackTrace: %v\n", e.Inner, e.Message, e.StackTrace) // 这里输出对应的数据 } } }
這種方式處理問題更加方便,但是仍然可能會有包循環引用的問題。
隱藏內部細節的錯誤處理
上述兩種方式,可以適應一些場景,不過都無法解決可能存在循環依賴的問題。為此,我們使用github.com/pkg/errors
的套件來解決問題,給出一個程式碼實例。
func New(message string) error
如果有現成的error,我們需要對他進行再次包裝處理,這時候有三個函數可以選擇。
//只附加新的信息 func WithMessage(err error, message string) error //只附加调用堆栈信息 func WithStack(err error) error //同时附加堆栈和信息 func Wrap(err error, message string) error
其實上面的包裝,很類似Java的異常包裝,被包裝的error,其實就是Cause,在前面的章節提到錯誤的根本原因,就是這個Cause。所以這個錯誤處理函式庫為我們提供了Cause函數讓我們可以得到最根本的錯誤原因。
func Cause(err error) error { type causer interface { Cause() error } for err != nil { cause, ok := err.(causer) if !ok { break } err = cause.Cause() } return err }
使用for迴圈一直找到最根本(最底層)的那個error。
相關文章教學推薦:golang教學
#以上是關於golang中的錯誤處理機制的詳細介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!