错误处理

错误类型(error)

error 在 Go 中是基础类型,以下代码是 error 在 Go 中的定义。只要实现了这个接口就是 error 类型。

type error interface {
    Error() string
}

标准库的 errors 包中实现了这个接口,在任何时候,当需要一个错误类型对象时,都可以用 errors 包的 errors.New() 方法接收合适的错误信息来创建。

Panic

在 Go 中,执行错误会触发运行时异常,相当于使用实现了接口类型 runtime.Error 调用内置函数 panic() 。运行时异常用来表示非常严重的不可恢复的错误。
一般不要随意使用 panic() 来终止程序,必须全力补救异常和错误以便让程序能继续执行。
在自定义包中需要做好错误处理和异常处理。

  1. 在包内部,应该用 recover() 对运行时的异常进行捕获。
  2. 向包的调用者返回错误值(而不是直接发出异常)。

recover() 的调用仅当它在 defer 修饰的函数中被直接调用时才有效。

Recover

recover() 内建函数用于从异常或错误场景中恢复,让程序可以从异常中重新获得控制权,停止中止过程进而恢复正常执行。
recover() 函数只能在 defer 修饰的函数中使用,用于取得异常传递过来的错误值。如果是正常执行,调用 recover() 函数会返回 nil,且没有其他效果。如果异常传递过来的是 nil 值,则 recover() 函数返回的值也是 nil,所以异常时的参数值不使用 nil。

关于 Defer

Defer 的三个规则

  1. defer 声明时,其后面函数参数会被实时解析。
package main

import (
   . "fmt"
)

func main() {
   i := 1
   defer Println("result1 =>", func() int {
       return i * 2
   }())
   i ++
   defer func() {
       Println("result2 =>", i * 2)
   }()
   i ++
}

程序输出

result2 => 6
result1 => 2
  1. defer 执行顺序为先进后出(FILO)。
package main

import (]
    . "fmt"
)

func main() {
    defer Println("!!!")
    defer Println("world")
    defer Println("hello")
}

程序输出

hello
world
!!!
  1. defer 可以读取函数的有名返回值。
package main

import (
    . "fmt"
)

func func1() (i int) {
    defer func() {
        i += 10
    }()
    return 0
}

func main() {
    Println("result =>", func1())
}

程序输出

result => 10

这是由于在 Go 中,return 语句不是原子操作,最先是所有返回值在进入函数时都会初始化为其类型的零值,退出返回时先给返回值赋值,然后执行 defer 语句,最后才是 return 操作。