错误处理
-
Go语言的错误设计是通过返回值的方式来让调用者对错误进行处理,通常我们的处理是对error类型的返回值进行if判断
f, err := os.Open("filename.ext") if err != nil { log.Fatal(err)
}
~~~
Error
-
error其实是一个接口类型,接口当中只有一个方法,并且该方法返回的是一个字符串
type error interface { Error() string
}
~~~
-
实现了error接口便自定义了error类型
type DBError struct {
}
func (dbError *DBError) Error() string {
return "数据库错误"
}
~~~
当我们使用定义的DBError进行错误的返回之后便会打印“数据库错误”的信息。如果想让我们的错误在使用的时候更自由附带信息的话可以再自定义的结构体中定义字段,比如:
type DBError struct {
s string
}
func (dbError *DBError) Error() string {
return dbError.s
}
存在的问题
经过上面的自定义之后,我们可以让error附带我们想要的信息,但是对于开发者还是不够的,我们有可能需要知道出错的更多信息,哪个文件中的哪一行代码,这样更方便我们定位问题
解决
- 解决方法可以让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函数,自带调用堆栈信息
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
上面的包装能够让我们找到错误的根本原因,本质上是库当中的Cause函数:
func Cause(err error) error {
type causer interface {
Cause() error
}
//for循环一直找到最根本的错误
for err != nil {
cause, ok := err.(causer)
if !ok {
break
}
err = cause.Cause()
}
return err
}
格式化打印
%s,%v //功能一样,输出错误信息,不包含堆栈
%q //输出的错误信息带引号,不包含堆栈
%+v //输出错误信息和堆栈
网友评论