go的error

  1. func main() {
  2. map1 :=make(map[int]string)
  3. map1[0]="a"
  4. map1[1]="b"
  5. val,ok := map1[0]
  6. if ok{
  7. fmt.Println(val)
  8. }else {
  9. fmt.Println("key为0不在map1中")
  10. }
  11. }

异常处理

  1. func test(){
  2. defer func() {
  3. if err:=recover();err!=nil{ //err不等于零值,说明发生了异常
  4. fmt.Println("err=",err)
  5. fmt.Println("发生错误我要做什么处理")
  6. }
  7. }()
  8. i:=10
  9. n:=0
  10. m:=i/n //错误,除数不能为0
  11. fmt.Println(m)
  12. }
  13. func main() {
  14. test()
  15. fmt.Println("main函数")
  16. }

创建一个被包装的 error

方式一:fmt.Errorf

使用 %w 参数返回一个被包装的 error

  1. err1 := errors.New("new error")
  2. err2 := fmt.Errorf("err2: [%w]", err1)
  3. err3 := fmt.Errorf("err3: [%w]", err2)
  4. fmt.Println(err3)
  5. // output
  6. err3: [err2: [new error]]

err2 就是一个合法的被包装的 error,同样地,err3 也是一个被包装的 error,如此可以一直套下去

方式二:自定义 struct

  1. type WarpError struct {
  2. msg string
  3. err error
  4. }
  5. func (e *WarpError) Error() string {
  6. return e.msg
  7. }
  8. func (e *WrapError) Unwrap() error {
  9. return e.err
  10. }

之前看过源码的同学可能已经知道了,这就是 fmt/errors.go 中关于 warp 的结构。
就,很简单。自定义一个实现了 Unwrap 方法的 struct 就可以了。

拆开一个被包装的 error

errors.Unwrap

  1. err1 := errors.New("new error")
  2. err2 := fmt.Errorf("err2: [%w]", err1)
  3. err3 := fmt.Errorf("err3: [%w]", err2)
  4. fmt.Println(errors.Unwrap(err3))
  5. fmt.Println(errors.Unwrap(errors.Unwrap(err3)))
  6. // output
  7. err2: [new error]
  8. new error

错误比较

IS

当多层调用返回的错误被一次次地包装起来,我们在调用链上游拿到的错误如何判断是否是底层的某个错误呢?
它递归调用 Unwrap 并判断每一层的 err 是否相等,如果有任何一层 err 和传入的目标错误相等,则返回 true。

  1. err1 := errors.New("new error")
  2. err2 := fmt.Errorf("err2: [%w]", err1)
  3. err3 := fmt.Errorf("err3: [%w]", err2)
  4. fmt.Println(errors.Is(err3, err2))
  5. fmt.Println(errors.Is(err3, err1))
  6. // output
  7. true
  8. true

AS

这个和上面的 errors.Is 大体上是一样的,区别在于 Is 是严格判断相等,即两个 error 是否相等。
而 As 则是判断类型是否相同,并提取第一个符合目标类型的错误,用来统一处理某一类错误。

  1. type ErrorString struct {
  2. s string
  3. }
  4. func (e *ErrorString) Error() string {
  5. return e.s
  6. }
  7. var targetErr *ErrorString
  8. err := fmt.Errorf("new error:[%w]", &ErrorString{s:"target err"})
  9. fmt.Println(errors.As(err, &targetErr))
  10. // output
  11. true

自定义异常

  1. func read(str string) (err error){
  2. if str!="aaa"{
  3. return errors.New("传的值不等于aaa!")//自定义异常
  4. }else {
  5. return nil
  6. }
  7. }
  8. func test1() {
  9. err :=read("aaa")
  10. if err!=nil{
  11. panic(err)//err!=nil说明发生了异常,用panic()输出异常并终止程序
  12. }
  13. fmt.Println("test1函数继续执行")
  14. }
  15. func main() {
  16. test1()
  17. fmt.Println("main函数继续执行")
  18. }

规则

同步执行,在panic发生的方法的祖辈层都能处理

  1. package main
  2. import (
  3. "fmt"
  4. "time"
  5. )
  6. func haha1() int {
  7. a:= []int{1,2,3}
  8. return a[3]
  9. }
  10. func hehe() {
  11. // 放在main中也行
  12. defer func() {
  13. if err:=recover();err!=nil{
  14. fmt.Println("异常处理")
  15. }
  16. }()
  17. haha1()
  18. }
  19. func main() {
  20. hehe()
  21. time.Sleep(time.Second)
  22. }

异步执行,必须得在被go 的方法中

  1. package main
  2. import (
  3. "fmt"
  4. "time"
  5. )
  6. func haha1() int {
  7. a:= []int{1,2,3}
  8. return a[3]
  9. }
  10. func hehe() {
  11. defer func() {
  12. if err:=recover();err!=nil{
  13. fmt.Println("异常处理")
  14. }
  15. }()
  16. haha1()
  17. }
  18. func main() {
  19. go hehe()
  20. time.Sleep(time.Second)
  21. }