go panic与recover分析及错误处理
先介绍一下什么叫error 类型
error 是一种类型,表示错误状态的类型,如果没有错误则是nil。直白点将:error 类型就是描述错误的一种类型。
panic 在golang goroutine 的作用 panic 官方文档介绍:
panic 是用来停止当前程序的执行。当一个方法调用panic。 当函数F调用panic时,F的正常执行立即停止。 但是任何有F推迟的函数都会运行,意思是F定义有defer关键字声明的函数会执行,然后F返回给它的调用者。 对于调用者G来说,F的调用就像调用panic 一样,终止G的执行并运行任何延迟(带有defer 关键字)的函数。 这种情况会持续下去,直到正在执行的goroutine中的所有功能都以相反的顺序停止。 此时,程序终止并报告错误情况,包括panic的参数值。最后这种情况可以通过调用recover 来恢复函数的运行。 函数 recover 介绍
recover内置函数允许一段程序管理一个正在paincing goroutine的行为。
在defer 定义的函数(不是由它调用的任何函数)内部执行一段recover 函数,通过recover函数执行来停止panic 函数的执行,并且可以找出给panic所传递的错误值。 如果在defer 函数之外调用恢复,它不会停止panic的执行。 在这种情况下,或者当goroutine没有panicing时,或者提供给panicing的参数为零时,恢复返回nil。 因此,recover函数的返回值报告协程是否正在遭遇panicing 。
panic函数就是往外扔错误,一层接一层往上扔直到当前程序不能运行为止,不想让panic 函数扔的错误导致程序挂掉,就得使用recover 函数来接收panic 错误或者说是阻挡panicing ,并且recover 函数可以将错误转化为error 类型。因为panic 错误不会让defer 关键字定义的函数也停止运行,就是说defer 关键字声明的函数或者代码即使遇到错误也会执行。 一个函数里面有defer 关键字声明一个函数(假设叫catch 函数)和要运行出错的代码,在catch 函数里面调用recover 函数。recover 会拦截错误,不会让错误往上扔,返回给调用者error(里面有错误的信息)类型 ,从而使goroutine 不挂掉。 上代码:
package main
import (
"fmt"
"errors"
)
func main() {
testError()
afterErrorfunc()
}
func testError() {
//defer catch()
panic(" "panic 错误"")
fmt.Println("抛出一个错误后继续执行代码")
}
func catch() {
if r := recover(); r != nil {
fmt.Println("testError() 遇到错误:", r)
var err error
switch x := r.(type) {
case string:
err = errors.New(x)
case error:
err = x
default:
err = errors.New("")
}
if err != nil {
fmt.Println("recover后的错误:",err)
}
}
}
func afterErrorfunc(){
fmt.Println("遇到错误之后 func ")
}
运行结果:
panic: "panic 错误"
goroutine 1 [running]:
main.testError()
E:/goCode/src/MyTestGo/src/com.dylan.main/panic/testpanic.go:16 +0x40
main.main()
E:/goCode/src/MyTestGo/src/com.dylan.main/panic/testpanic.go:10 +0x27
Process finished with exit code 2
当panic 函数执行的时候导致后面函数 afterErrorfunc() 不能执行,main函数也抛出一个错误,整个程序异常退出。 通过defer 关键字调用 catch函数。
func testError() {
defer catch()
panic(" "panic 错误"")
fmt.Println("抛出一个错误后继续执行代码")
}
程序运行结果:
testError() 遇到错误: "panic 错误"
recover后的错误: "panic 错误"
遇到错误之后 func
Process finished with exit code 0
分析:程序正常结束,没有因为panic(错误)而到导致程序终止挂掉。错误被recover 函数接收,转化为error类型的错误,最后输出“ recover后的错误: “panic 错误” ” 而且后面 afterErrorfunc()执行。
一般在写的时候这么写 不用定义catch 函数:
func main() {
testError()
afterErrorfunc()
}
func testError() {
defer func() {
if r := recover(); r != nil {
fmt.Println("testError() 遇到错误:", r)
}
}()
panic(" "panic 错误"")
fmt.Println("抛出一个错误后继续执行代码")
}
func catch(err error) {
if r := recover(); r != nil {
fmt.Println("testError() 遇到错误:", r)
switch x := r.(type) {
case string:
err = errors.New(x)
case error:
err = x
default:
err = errors.New("")
}
}
}
func afterErrorfunc() {
fmt.Println("遇到错误之后 func ")
}
在发生panic 函数里面加入下述代码就可以拦截panicing, 并且不让程序挂掉和显示错误信息。
defer func() {
if r := recover(); r != nil {
fmt.Println("testError() 遇到错误:", r)
}
}()
最后如果想将错误信息返回给调用者可以这么做:
func main() {
err := testError()
if err != nil {
fmt.Println("main 函数得到错误类型:", err)
}
afterErrorfunc()
}
func testError() (err error) {
defer func() {
if r := recover(); r != nil {
fmt.Println("testError() 遇到错误:", r)
switch x := r.(type) {
case string:
err = errors.New(x)
case error:
err = x
default:
err = errors.New("")
}
}
}()
panic(" "panic 错误"")
fmt.Println("抛出一个错误后继续执行代码")
return nil
}
func catch(err error) {
if r := recover(); r != nil {
fmt.Println("testError() 遇到错误:", r)
switch x := r.(type) {
case string:
err = errors.New(x)
case error:
err = x
default:
err = errors.New("")
}
}
}
func afterErrorfunc() {
fmt.Println("遇到错误之后 func ")
}
提前声明一个error 类型的变量。把错误信息传递给error变量,再把error变量返回给调用者。
- 一个数字截取引发的精度问题(二)
- 【独家推送】GoogLeNet构建技术分析因子的模式识别基于TensorFlow
- 一个数字截取引发的精度问题(一)
- 基于TLS1.3的微信安全通信协议mmtls介绍
- 在 WCF 中使用高效的 BinaryFormatter 序列化
- Visual Studio 2012 中的ASP.NET Web API
- gradeview可拖动效果实现
- 【Python量化投资】拟合具有非平稳特征的神经网络对股票进行预测
- 使同事羡慕不已的8个npm命令
- JavaScript代码风格要素
- 从 WebAPI Beta 更新到WebAPI RC
- 再谈异步
- canvas-画线
- canvas-入门
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Go by Example 中文版: 互斥锁
- Idea初始化配置大全,以后重装再也不用各种百度了
- 使用这种技巧,可以大大地提高前端布局效率
- Element-UI表格组件实现行拖拽排序
- Vue自定义指令实现拖拽功能
- 小程序 Canvas 层级问题
- JDK 8 新特性之函数式编程 → Stream API
- golang 单元测试框架实践
- 想要成为前端Star 吗?一首歌时间将React/Vue 应用Docker 化
- 60亿次for循环,原来这么多东西
- 不要再问我 in,exists 走不走索引了...
- 知乎太可恶了,一言不合就封号?
- 5年Java开发经验,面试挂在MySQL InnoDB上!大厂究竟多看重MySQL?
- 是你们的力量,让知乎看见了!
- 视屏面试传输协议到底是TCP还是UDP