10 panic 和 error

[TOC]

panic 和 error

异常 panic

运行时错误panic使用场景

  • 程序遇到无法正常执行下去的错误,主动调用panic函数结束程序运行。

  • 在调试程序时,通过主动调用panic实现快速退出,panic打印出的堆栈能够更快地定位错误。

异常是发生了未知的行为,错误的类型不在预定义的范围之内。

  • 异常又称为未捕获的错误。程序在执行时发生未预先定义的错误,程序编译器和运行时都没有及时将其捕获处理,而是由操作系统进行异常处理。

  • 无法完全避免运行时错误的发生,只能尽量减少其发生的概率,避免因为一个panic引发整个程序崩溃。

panic与recover

Go运行时错误主要通过panic()和recover()两个函数处理,panic()主动抛出错误,recover()捕获panic()抛出的错误。

  • panic 函数签名

panic(v interface{})
  • recover 函数签名

  • 引发panic的两种情况,程序主动调用panic函数或者产生运行时错误由运行时检测并抛出。

  • panic发生后,程序会从调用panic的函数位置或发生panic的地方立即返回,逐层向上执行函数的defer语句,然后逐层打印函数调用栈,直到被recover捕获或运行到最外层函数而退出。

  • panic不但可以在函数正常流程中抛出,在defer逻辑里也可以再次调用panic或抛出panic。defer里面的panic能够被后续执行的defer捕获。

defer 和 recover()配合使用捕获异常

recover用来捕获panic,阻止panic继续向上传递。

  • recover只有在defer后面的函数体内被直接调用才能捕获panic终止异常,否则返回nil,panic继续向上传递。

  • 无法捕获,defer 直接调用recover()

  • 正确捕获,recover()写在defer的函数体内

多个panic抛出,只有最后一个panic会被捕获

延迟抛出多个panic,只有最后一个panic被捕获,但是其它panic也不会继续向上传递导致程序终止,也就是只需要一个recover就能让函数按照正常流程执行。

  • 案例中只捕获了最后抛出的错误1

一个函数调用栈中先进的才可以捕获后进的panic

main()函数无法捕获init()函数的panic

  • init()函数中抛出的panic无法在main()函数中捕获,因为init()函数不是main()函数调用的。而init()函数也无法捕获main()函数中的panic,因为main()函数也不是init()函数调用的。

属于一个函数调用栈中先进的捕获后进的panic

  • test()函数是main()函数调用的,因此main()函数可以捕获test()函数中的panic

函数无法捕获协程(goroutine)内的panic

开启的协程中出现panic,开启协程的函数是无法捕获的

错误 error

为保证程序的健壮性,需要主动在程序的分支流程上使用recover()拦截运行时错误。Go除了panic和recover异常处理方式外还有使用error错误类型。

接口类型 error

Go内置错误接口类型error,任何类型只要实现Error() string 方法,都可以传递error接口类型变量。

  • Go中常见错误处理方式是将error作为函数最后一个返回值,在调用函数时通过检测其返回的error值是否为nil来进行错误处理。

标准库函数封装实现error接口

Go标准库中提供两个函数返回实现了error接口的具体类型实例,一般的错误可以使用两个函数进行封装,遇到复杂的错误再自定义错误类型。

  • 函数1:errors.New(string)

  • 函数2:fmt.Errorf(string,...interface{})

自定义error

  • 自定义错误比较,比较的是Error() string 返回值,字符串比较。

error 陷阱

错误的自定义 error 返回值

  • 例子:

  • 输出结果:

调用 fun2() 函数以后 err 就不是 nil,错误地进入了 if,但是 fun2() 函数的返回值是 nil

  • 错误1:这是一种代码编写不规范引起的错误,func fun2() *myError 应改为 func fun2() error,返回值可以是具体实现。

  • 错误2:直接调用 fun2() 函数,却不会错误地进入 if,???,这就是坑,因此编写代码要规范,错误返回类型一律是 error,返回值可以是具体实现。

Last updated