錯誤處理
-
Go語言的錯誤設(shè)計是通過返回值的方式來讓調(diào)用者對錯誤進行處理西雀,通常我們的處理是對error類型的返回值進行if判斷
f, err := os.Open("filename.ext") if err != nil { log.Fatal(err)
}
~~~
Error
-
error其實是一個接口類型,接口當(dāng)中只有一個方法镣隶,并且該方法返回的是一個字符串
type error interface { Error() string
}
~~~
-
實現(xiàn)了error接口便自定義了error類型
type DBError struct {
}
func (dbError *DBError) Error() string {
return "數(shù)據(jù)庫錯誤"
}
~~~
當(dāng)我們使用定義的DBError進行錯誤的返回之后便會打印“數(shù)據(jù)庫錯誤”的信息莫绣。如果想讓我們的錯誤在使用的時候更自由附帶信息的話可以再自定義的結(jié)構(gòu)體中定義字段,比如:
type DBError struct {
s string
}
func (dbError *DBError) Error() string {
return dbError.s
}
存在的問題
經(jīng)過上面的自定義之后,我們可以讓error附帶我們想要的信息,但是對于開發(fā)者還是不夠的,我們有可能需要知道出錯的更多信息供填,哪個文件中的哪一行代碼,這樣更方便我們定位問題
解決
- 解決方法可以讓error記錄堆棧信息
type stack []uintptr
type errorString struct {
s string
*stack
}
func callers() *stack {
const depth = 32
var pcs [depth]uintptr
n := runtime.Callers(3, pcs[:])
var st stack = pcs[0:n]
return &st
}
func New(text string) error {
return &errorString{
s: text,
stack: callers(),
}
}
以上源碼是github.com/pkg/errors錯誤處理庫的源碼罢猪。它的使用很簡單近她,如果我們要生成一個錯誤,可以使用New函數(shù)膳帕,自帶調(diào)用堆棧信息
func New(message string) error
若有現(xiàn)成的error粘捎,我們需要對他進行再次包裝處理,有三個函數(shù)可供選擇
//只附加新的信息
func WithMessage(err error, message string) error
//只附加調(diào)用堆棧信息
func WithStack(err error) error
//同時附加堆棧和信息
func Wrap(err error, message string) error
上面的包裝能夠讓我們找到錯誤的根本原因危彩,本質(zhì)上是庫當(dāng)中的Cause函數(shù):
func Cause(err error) error {
type causer interface {
Cause() error
}
//for循環(huán)一直找到最根本的錯誤
for err != nil {
cause, ok := err.(causer)
if !ok {
break
}
err = cause.Cause()
}
return err
}
格式化打印
%s,%v //功能一樣攒磨,輸出錯誤信息,不包含堆棧
%q //輸出的錯誤信息帶引號汤徽,不包含堆棧
%+v //輸出錯誤信息和堆棧