Go Error处理

错误

在go中,错误是可以被接受的,一般把错误返回给函数调用者,由函数调用者自行决定如何处理错误。
如Atoi函数的例子。

func Atoi(s string) (int, error) {
    // ... 省略
   return int(i64), err
}

// 使用模式
func main() {
   i,err:=strconv.Atoi("a")
   if err!=nil {
      fmt.Println(err)
   }else {
      fmt.Println(i)
   }
}

error工厂函数

通过工厂函数创建一个error

func New(text string) error {
   return &errorString{text}
}

// errorString is a trivial implementation of error.
type errorString struct {
   s string
}

func (e *errorString) Error() string {
   return e.s
}

error断言

将error接口类型强转成更加携带了更多错误信息的子类类型

sum, err := add(-1, 2)
if cm,ok:=err.(*commonError);ok{ // 进行错误断言
   fmt.Println("错误代码为:",cm.errorCode,",错误信息为:",cm.errorMsg)
} else {
   fmt.Println(sum)
}

错误嵌套

fmt.Errorf函数

假如我们现在要将一个基础error包装成一个信息更加多的errorPlus错误,我们可以

type errorPlus struct{
    err error
    msg string
}

以上方式实现了error的嵌套,但是这样的嵌套需要额外的编写代码,所以go提供了fmt.Errorf函数,来帮助我们进行Error嵌套。


func main() {
   err := errors.New("I am base error")
   err = fmt.Errorf("sub error xxx and base error msg is %w", err)

   println(err.Error())
}

errors.Unwrap函数

取得套娃error的base error


func main() {
   err := errors.New("I am base error")
   err = fmt.Errorf("sub error xxx and base error msg is %w", err)

   println(err.Error())
   err = errors.Unwrap(err)
   println(err.Error()) // I am base error
}

errors.Is函数

判断两个error是否具备嵌套关系.
errors.Is(A,B), 其实就是判断B是否在A的嵌套链当中,B的范围不能超过A。


func main() {
   err := errors.New("I am base error")
   errWarp := fmt.Errorf("sub error xxx and base error msg is %w", err)
   println(errors.Is(err, errWarp)) // false
   println(errors.Is(errWarp, err)) // true
}

errors.As函数

将base error转换成更具体的error

var cm *commonError

if errors.As(err,&cm){

   fmt.Println("错误代码为:",cm.errorCode,",错误信息为:",cm.errorMsg)

} else {

   fmt.Println(sum)

}

defer 关键字

defer关键字有点类似Java中的finally代码块,defer也是用来关闭资源的。


func main() {

   defer func() {
      println("one ")
   }()
   defer func() {
      println("two ")
   }()
   defer func() {
      println("three ")
   }()
}
// 执行顺序. three two one

panic

一旦发生了panic,那么整个程序将无法继续运行,它的错误程度要比error深。我们可以自己抛出panic异常。
如果不影响程序的正常运行,使用error即可。

func main(){
    // 一些逻辑
    panic("this is pannic")
}

recover

recover可以拿到panic中的参数,recover一般和defer关键字搭配使用。

func main() {

   defer func() {

      if p:=recover();p!=nil{

         fmt.Println(p)

      }

   }()

   panic("some panic msg")

}