?error接口类型

定义

  1. Go语言中返回的 error 类型究竟是什么呢?查看Go语言的源码就会发现 error 类型是一个非常简单的接口类型,如下所示:
    ?错误处理 - 图1
  2. Go 语言的标准库代码包 errors 为用户提供如下方法:
    ?错误处理 - 图2
    所以errors包里提供两种方法(注意开头要有<font style="color:rgb(0,0,0);">import "errors"</font>
使用方法 场景
方式1 err:= errors.New(...) 由于是interface接口类型,可以返回任意类型信息,string/int/…皆可 1. 创建一个 error 最简单的方法就是调用 errors.New 函数,它会根据传入的错误信息返回一个新的 error
2. 一般情况下,如果函数需要返回错误,就将 error 作为多个返回值中的最后一个(但这并非是强制要求)。
方式2 创建error接口类型的变量,调用方法, <font style="color:rgb(0,0,0);">errors.Error(...)</font> 自定义错误
  1. fmt包里,其实也内置了方法

——方式3,语法fmt.Errorf("%...", ....)方框内像是printf函数一样打印

应用

:::info 实际运用我们并我需要知道实际代码如何,我们先来看看基本用法

:::

  1. 方式1:fmt.Errorf("%...", ....)方框内像是printf函数一样打印
    实例
    ?错误处理 - 图3
    结果:?错误处理 - 图4
  2. 方式2:引入包import "errors"error,New("%...", ...)
    实例
    ?错误处理 - 图5
    结果:?错误处理 - 图6

:::info 实例2:err:= errors.New(...)

:::

b = 0,出错

?错误处理 - 图7结果:?错误处理 - 图8

b≠0,未出错

?错误处理 - 图9结果?错误处理 - 图10

:::info 实例3:除了上面的 errors.New 用法之外,我们还可以使用 error 接口自定义一个 Error() 方法,来返回自定义的错误信息。

:::

  1. package main
  2. import (
  3. "fmt"
  4. "math"
  5. )
  6. type dualError struct {
  7. Num float64
  8. problem string
  9. }
  10. func (e dualError) Error() string {
  11. return fmt.Sprintf("Wrong!!!,because \"%f\" is a negative number", e.Num)
  12. }
  13. func Sqrt(f float64) (float64, error) {
  14. if f < 0 {
  15. return -1, dualError{Num: f} //????
  16. }
  17. return math.Sqrt(f), nil
  18. }
  19. func main() {
  20. result, err := Sqrt(-13)
  21. if err != nil {
  22. fmt.Println(err)
  23. } else {
  24. fmt.Println(result)
  25. }
  26. }

?错误处理 - 图11

想法

  1. error不会去感知错误,要我们自己设置发生错误的场景,然后把error.New()/<font style="color:rgb(0,0,0);">errors.Error(...)</font>作为返回值进行返回
  2. errors.New(...)<font style="color:rgb(0,0,0);">errors.Error(...)</font>一个是函数,一个是方法,但使用的时候,感觉和字符串无差别
  3. 还有很多错误类型为了解,之后分析这里综合了一下

panic

用于比较致命的错误,如数组访问越界、空指针引用等

在通常情况下,向程序使用方报告错误状态的方式可以是返回一个额外的 error 类型值。 但是,当遇到不可恢复的错误状态的时候,如数组访问越界、空指针引用等,这些运行时错 误会引起 painc 异常。这时,上述错误处理方式显然就不适合了。反过来讲,在一般情况下, 我们不应通过调用 panic 函数来报告普通的错误,而应该只把它作为报告致命错误的一种方式。当某些不应该发生的场景发生时,我们就应该调用 panic。 一般而言,当 panic 异常发生时,程序会中断运行,并立即执行在该 goroutine(可以先理解成线程,在中被延迟的函数(defer 机制)。随后,程序崩溃并输出日志信息。日志信息包括 panic value 和函数调用的堆栈跟踪信息。不是所有的 panic 异常都来自运行时,直接调用内置的 panic 函数也会引发 panic 异常;panic函数接受任何值作为参数

语法:panic("...错误时返回的内容")

作用:显式调用panic函数,导致程序中断

实例1——自己主动调用:

?错误处理 - 图12

实例2——程序出错编译器调用panic,如数组越界:

?错误处理 - 图13

recover

定义

语法:recover()一个函数

  1. 只在defer语句中有效
  2. 可感知panic,其范围: 1. 局部作用域 2. 延迟调用中引发的错误,可被后续延迟调用捕获,但仅最后⼀个错误可被捕获,见实例2
  3. 若发生panic,recover 会使程序从 panic 中恢复,并返回 panic value。导致 panic 异常的函数不会继续运行,但能正常返回。
  4. 在未发生 panic 时调用 recover,recover 会返回 nil。

应用

实例分析

一般会嵌入函数,defer func...

  1. 单独recover()
    1. panic的时候,返回错误信息,此处是index out of range,也就是数组越界
      ?错误处理 - 图14
    2. 不panic的时候,返回nil
      ?错误处理 - 图15
  2. 嵌入if判断语句
    上面不够完美,我们希望出错时候返回错误信息,不出错就正常运行,不返回,故习惯上嵌入if判断语句先对recover进行判断,err != nil

    1. 易错:感知范围是局部作用域,if 结构中并未出错,只会返回nil
      ?错误处理 - 图16
    2. 正确:
      ?错误处理 - 图17
  3. 延迟调用中引发的错误,可被后续延迟调用捕获,但仅最后⼀个错误可被捕获(注意多个defer语句就算其中一个发生panic,程序不会中止,会忽略然后继续执行,顺序是先进后出,后进先出,堆栈顺序):
    ?错误处理 - 图18

总结

  1. recover()是一个函数,会返回值,panic value/ nil
  2. 注意其范围
    1. 局部作用域
    2. 其它defer语句的错误,仅最后⼀个错误可被捕获
  3. 一般外面会套两层衣服,一件衣服是defer的函数,习惯是匿名函数,另一件是if 判断语句