go错误处理续笔记

540 阅读3分钟

「这是我参与2022首次更文挑战的第24天,活动详情查看:2022首次更文挑战」。

0 环境

1 error断言

和接口中的断言类似,它那是定义一个接口变量,接口变量.(接收者类型)断言。而这里是先获取到错误返回值(假如没有实现接口,运行断言时,会报错缺少接口类型的。),在通过错误返回值.(类型)断言,判断是否为空,编写相对应的代码。如下代码:虽然在assertAddHeight1()中,error1它是universalError指针类型,但universalError指针类型已经实现了error接口,这也可以说明addHeight1()返回值类型可以用error定义的原因。

type universalError struct {
   // 错误状态
   errorStatus int
   // 错误信息
   errorMsg string
}

func (ue *universalError) Error() string {
   return ue.errorMsg
}

func addHeight1(heightMin, heightMax int) (int, error) {
   if heightMin < 150 || heightMax < 180 {
      return 150,&universalError{
         errorStatus: 400,
         errorMsg: "heightMin不能小于150,heightMax不能小于180",
      }
   } else {
      return heightMin + heightMax, nil
   }
}

func assertAddHeight1()  {
   sum, error1 := addHeight1(149,181)
   ue, result := error1.(*universalError)
   if result {
      fmt.Println("错误状态 -->", ue.errorStatus,"\n错误信息 -->", ue.errorMsg)
   } else {
      fmt.Println(sum)
   }
}

func main() {
   assertAddHeight1()
}

2 错误嵌套

1 Error Wrapping(合)

上面的自定义错误,需要实现错误接口,在返回错误信息。现在呢,变了,需要多个错误共存,不仅仅只有这一个错误信息,在不改变这个错误信息的情况下,在新建出来新的错误,拓展(嵌套)多个error,但是之前的方式是:先定义结构体,在里面不停拓展,在用接口实现它,可以但太过麻烦了,有么有更好的方式呢? Error Wrapping它来了,一股浓厚的借鸡生蛋的味道,在鸡窝里,借鸡(已有的错误)生蛋(新的错误),最终的结果是:既有鸡(已有的错误),还有新鲜美味的蛋(新的错误),也就是:已有的错误和新的错误共存。

fmt.Errorf函数里加个%w,对了,里面的那种鸡,我没写错哦,是那种鸡

image.png

2 errors.Unwrap函数(解)

如果说上面的Error Wrapping是给鸡下套(包裹嵌套),那errors.Unwrap就是给鸡解套。

image.png

3 errors.Is函数(判断)

判断两个error是否相同(判断第一个参数是否相等/包含第二个参数)。假设 鸡 蛋代表嵌套error,鸡代表原来的错误。比如Is传入a,b两个参数,Is(a, b) --> a包含b则为true,(鸡 蛋,鸡),而false,(鸡, 鸡 蛋)肯定不包含呀。

image.png

4 errors.As函数(断言)

 当有了嵌套error后,之前的断言就不能用,这时替代品errors.As()出现了。

改写上面error断言的例子,用As来实现。 image.png

3 总结

首先学习了error的断言,虽然和自定义接口的断言有区别,但也需要实现error接口并且返回值为error。面对多个error,并且需要在旧的错误的基本上,添加新的错误,保证新旧共存,error的嵌套帮我们很好的解决了这个问题,它提供了嵌套和解套,以及error的相同判断和嵌套error断言的写法(之前的断言不在适用)。