[Go] panic 和 recover
通常情况下,函数向其调用方报告错误的方式都是返回一个 error 类型的值。但是,当遇到致命错误的时候,很可能会使程序无法继续运行。这时,上述错误处理方式就太不适合了,Go 推荐通过调用 panic 函数来报告致命错误。
1. panic
为了报告运行期间的致命错误,Go 内建了专用函数 panic,该函数用于停止当前的控制流程并引发一个运行时恐慌。它可以接受一个任意类型的参数值,不过这个参数值的类型常常会是 string 或者 error,因为这样更容易描述运行时恐慌的详细信息。请看下面的例子:
func main() {
outerFunc()
}
func outerFunc() {
innerFunc()
}
func innerFunc() {
panic(errors.New("An intended fatal error!"))
}
当调用 innerFunc 函数中的 panic 函数后,innerFunc 的执行会被停止。紧接着,流程控制权会交回调用方 outerFunc 函数。然后,outerFunc 函数的执行也将被停止。运行时恐慌就这样沿着调用栈反方向进行传播,直至到达当前 goroutine 的调用栈的最顶层。一旦达到顶层,就意味着该 goroutine 调用栈中所有函数的执行都已经被停止了,程序已经崩溃。
当然,运行时恐慌并不都是通过调用 panic 函数的方式引发的,也可以由 Go 的运行时系统来引发。例如:
myIndex := 4
ia := [3]int{1, 2, 3}
_ = ia[myIndex]
这个示例中的第 3 行代码会引发一个运行时恐慌,因为它造成了一个数组访问越界的运行时错误。这个运行时恐慌就是由 Go 的运行时系统报告的。它相当于我们显示地调用 panic 函数并传入一个 runtime.Error 类型的参数值。顺便说一句,runtime.Error 是一个接口类型,并且内嵌了 Go 内置的 error 接口类型。
显然,我们都不希望程序崩溃。那么,怎样“拦截”一个运行时恐慌呢?
2. recover
运行时恐慌一旦被引发,就会向调用方传播直至程序崩溃。Go 提供了专用于“拦截”运行时恐慌的内建函数 recover,它可以使当前的程序从恐慌状态中恢复并重新获得流程控制权。recover 函数被调用后,会返回一个 interface{} 类型的结果。如果当时的程序正处于运行时恐慌的状态,那么这个结果就会是 非 nil 的。
recover 函数应该与 defer 语句配合起来使用,例如:
defer func() {
if p := recover(); p != nil {
fmt.Printf("Recovered panic: %s\n", p)
}
}()
把此类代码放在函数体的开始处,这样可以有效防止该函数及其下层调用中的代码引发运行时恐慌。一旦发现 recover 函数的调用结果是 非 nil,就应该采取相应的措施。
值得一提的是,Go 标准库中有一种常见的用法值得我们参考。请看标准库代码包 fmt 中的 Token 函数的部分声明:
func (s *ss) Token(skipSpace bool, f func(rune) bool) (tok []byte, err error) {
defer func() {
if e := recover(); e != nil {
if se, ok := e.(scanError); ok {
err = se.err
} else {
panic(e)
}
}
}()
// 省略部分代码
}
在 Token 函数包含的 延迟函数 中,当运行时恐慌携带值的类型是 fmt.scanError 时,这个值就会被赋值给代表结果值的变量 err,否则运行时恐慌就会被重新引发。如果这个重新引发的运行时恐慌传递到了调用栈的最顶层,那么标准输出上就会打印类似这样的内容:
panic: <运行时恐慌被首次引发时携带的值的字符串形式> [recovered]
panic: <运行时恐慌被重新引发时携带的值的字符串形式>
goroutine 1 [running]:
main.func.001()
<调用栈信息> goroutine 2 [runnable:]
exit status 2
这里展现的惯用法有 2 个,如下:
- 可以把运行时恐慌的携带值转换为 error 类型值,并当作常规结果返回给调用方。这样既阻止了恐慌的扩散,又传递了引起恐慌的原因。
- 检查运行时恐慌携带值的类型,并根据类型做不同的后续动作,这样可以精确地控制程序的错误处理行为。
摘自:《Go 并发编程实战(第二版) . 郝林》
[Go] panic 和 recover的更多相关文章
- 【Go入门教程3】流程(if、goto、for、switch)和函数(多个返回值、变参、传值与传指针、defer、函数作为值/类型、Panic和Recover、main函数和init函数、import)
这小节我们要介绍Go里面的流程控制以及函数操作. 流程控制 流程控制在编程语言中是最伟大的发明了,因为有了它,你可以通过很简单的流程描述来表达很复杂的逻辑.Go中流程控制分三大类:条件判断,循环控制和 ...
- 【GoLang】panic defer recover 深入理解
唉,只能说C程序员可以接受go的错误设计,相比java来说这个设计真的很差劲! 我认为知乎上说的比较中肯的: 1. The key lesson, however, is that errors ar ...
- panic和recover的使用规则
转自个人博客 chinazt.cc 在上一节中,我们介绍了defer的使用. 这一节中,我们温习一下panic和recover的使用规则. 在golang当中不存在tye ... catch 异常处理 ...
- go语言中使用defer、panic、recover处理异常
go语言中的异常处理,没有try...catch等,而是使用defer.panic.recover来处理异常. 1.首先,panic 是用来表示非常严重的不可恢复的错误的.在Go语言中这是一个内置函数 ...
- Go基础系列:defer、panic和recover
defer关键字 defer关键字可以让函数或语句延迟到函数语句块的最结尾时,即即将退出函数时执行,即便函数中途报错结束.即便已经panic().即便函数已经return了,也都会执行defer所推迟 ...
- Golang错误处理函数defer、panic、recover、errors.New介绍
在默认情况下,当发生错误(panic)后,程序就会终止运行 如果发生错误后,可以捕获错误,并通知管理人员(邮件或者短信),程序还可以继续运行,这当然无可厚非 errors.New("错误信息 ...
- [日常] Go语言圣经-Panic异常,Recover捕获异常习题
Go语言圣经-Panic异常1.当panic异常发生时,程序会中断运行,并立即执行在该goroutine中被延迟的函数(defer 机制)2.不是所有的panic异常都来自运行时,直接调用内置的pan ...
- Golang异常处理-panic与recover
Golang异常处理-panic与recover 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在程序设计中,容错是相当重要的一部分工作,在 Go中它是通过错误处理来实现的,err ...
- GOLANG错误处理最佳方案errors wrap, Defer, Panic, and Recover
Simple error handling primitives: https://github.com/pkg/errors Defer, Panic, and Recover: ...
- 理解Defer、Panic和Recover
刚开始的时候理解如何使用Defer和Recover有一点怪异,尤其是使用了try/catch块的时候.有一种模式可以在Go中实现和try/catch语句块一样的效果.不过之前你需要先领会Defer.P ...
随机推荐
- 在xampp与phpstorm环境下安装xdebug[转]
XDebug是什么 很多PHP程序员调试使用echo.print_r().var_dump().printf()等,虽然对于有较丰富开发经验的程序员来说这些也已经足够了,他们往往可以在程序执行的过程中 ...
- Ubuntu 查看CPU温度
按照这篇文章: http://www.webupd8.org/2014/06/psensor-updated-with-option-to-display.html
- python代码在IDE下调试设置命令行参数
带命令行参数的代码在IDE下调试,需要把参数赋值,本文mark一下具体的命令行参数在代码中赋值方法. if __name__ == "__main__": sys.argv = [ ...
- windows下使用pip安装python模块lxml
pip install lxml 1 1 会有如下问题: 结果一路解决下去,解决了一个坑还是有一个坑,遂放弃,查找有没有别的解决办法. 亲测使用wheel+pip可以成功安装lxml! wheel本 ...
- 拓展中国剩余定理(exCRT)摘要
清除一个误区 虽然中国剩余定理和拓展中国剩余定理只差两个字,但他俩的解法相差十万八千里,所以会不会CRT无所谓 用途 求类似$$\begin{cases}x \equiv b_{1}\pmod{a_{ ...
- windows下安装Apache
2014年3月10日 13:22:53 选择vc9版本的Apache,这个时候了,大多PHP扩展或者PHP的windows版本已经很流行vc9编译的版本了,为了方便安装扩展,所以选择vc9版本 htt ...
- R语言学习笔记:使用tcltk包显示进度条
一般在跑耗时较长的程序时,我们不知道程序到底有没有正常跑着,或者在爬虫的时候不知道爬到什么时候断了.因此可以添加进度条来显示当前进度,观察进度是否有进展.当进度条卡住的时候,可以判断程序断线,从而可以 ...
- watch案例解析(element-ui el-select 无法选中问题剖析)
fire 读在最前面: 1.此文章衔接Vue 虚拟Dom 及 部分生命周期初探,相关整体知识点请先阅读后再继续本文阅读 问:子组件中明明有watch value,为什么this.$emit('inpu ...
- Windows下安装Tensorflow(python3.6):记录过程
安装前的情况: 之前使用的都是python2.7,但是tensorflow不支持2.x版本,那只有基于在3.x版本进行安装了 前段时间,我安装VS2017的时候安装了python3.6于是想在此基础上 ...
- 在Win10下搭建web服务器,使用本机IP不能访问,但是使用localhos或127.0.0.1可以正常访问的解决办法
最近在在Win10下搭建web服务器,发现通过windows自带的浏览器win10 edge浏览器使用本机IP不能放问,但是使用localhos或127.0.0.1可以正常访问, 后来无意发现,使用w ...