Go异常处理机制panic和recover


recover


使用panic抛出异常后, 将立即停止当前函数的执行并运行所有被defer的函数,然后将panic抛向上一层,直至程序crash。但是也可以使用被defer的recover函数来捕获异常阻止程序的崩溃,recover只有被defer后才是有意义的。

func main() {

 print(123)

 print(456)
 panic("throw an error")

 print(678//IDE会有提示: Unreachable code

}

结果:

123456panic: throw an error

goroutine 1 [running]:
main.main()
    /Users/shuangcui/explore/panicandrecover.go:31 +0x67

使用recover()捕获异常:

func main() {

 print(123)

 defer func() {
  if err := recover(); err != nil {
   print("recover it")
  }
 }()

 print(456)
 panic("throw an error")

 print(678//IDE会有提示: Unreachable code

}

结果为:

123456recover it

如果有两个recover,则捕获异常的是后一个

func main() {

 print(123)

 defer func() {
  if err := recover(); err != nil {
   print("recover it")
  }
 }()

 defer func() {
  if err := recover(); err != nil {
   print("复原!")
  }
 }()

 print(456)
 panic("throw an error")

 print(678//IDE会有提示: Unreachable code

}

结果为:

123456复原!

panic之后的任何代码都不会继续执行


前提是panic不在if里面


package main

import "fmt"

func main() {
 defer_call()
 fmt.Println("333 Helloworld")
}

func defer_call() {
 defer func() {
  fmt.Println("11111")
 }()

 defer func() {
  fmt.Println("22222")
 }()

 defer func() {
  if r := recover(); r != nil {
   fmt.Println("Recover from r : ", r)
  }
 }()

 defer func() {
  fmt.Println("33333")
 }()

 fmt.Println("111 Helloworld")

 panic("Panic 1!")


    //使用panic抛出异常后, 将立即停止当前函数的执行并运行所有被defer的函数,然后将panic抛向上一层, 直至程序crash

    //但是也可以使用被defer的recover函数来捕获异常阻止程序的崩溃,recover只有被defer后才是有意义的。

 panic("Panic 2!"//panic1之后的panic2没有任何机会会被执行, panic2之后的任何代码更没有任何机会被执行

 fmt.Println("222 Helloworld")
}

输出为:

111 Helloworld
33333
Recover from r :  Panic 1!
22222
11111
333 Helloworld

对于goroutine中的panic,协程外面的recover是无法恢复的;goroutine中的recover,同样无法恢复协程外的panic


alt

但协程中的recover可以恢复协程中的panic

package main

import (
 "fmt"
 "time"
)

func main() {

 go func() {
  defer func() {
   if err := recover(); err != nil {
    fmt.Println("recover err:", err)
   }
  }()
  panic("里面出错了")
 }()

 //panic("外面出错了")

 time.Sleep(1 * time.Second)

}

输出为:

recover err 里面出错了


主方法中的recover,也可以恢复子方法里的panic


但如果go subfunc(),则同样无法捕获subfunc中的异常

func main() {

 fmt.Println(123)

 defer fmt.Println(999)

 defer func() {
  if err := recover(); err != nil {
   fmt.Println("恢复异常:",err)
  }

 }()
 subfunc()

}

func subfunc() {

 defer fmt.Println(888)
 panic("出现了bug")

 defer fmt.Println(456)

}

结果为:

123
888
恢复异常: 出现了bug
999



因为panic发生的时候,panic函数后面的语句都不会执行了,所以recover函数不能放在panic语句后面执行,而要放在defer函数中执行。

使用 panic 抛出异常后,函数执行将从调用 panic 的地方停止,如果函数内有 defer 调用,则执行 defer 后边的函数调用,如果 defer 调用的函数中没有捕获异常信息,这个异常会沿着函数调用栈往上传递,直到 main 函数仍然没有捕获异常,将会导致程序异常退出


如何区别使用 panic 和 error 两种方式?

惯例是:导致关键流程出现不可修复性错误的使用 panic ,其他使用 error 。

panic 和 recover 的组合有如下特性:

  • 有 panic 没 recover ,程序宕机。
  • 有 panic 也有 recover ,程序不会宕机,执行完对应的 defer 后,从宕机点退出当前函数后继续执行。



recover能捕获所有错误吗?


不能!

Go 有哪些无法恢复的致命场景?

  • 并发读写 map fatal error: concurrent map read and map write
  • 堆栈内存耗尽(如递归)
runtime: goroutine stack exceeds 1000000000-byte limit
runtime: sp=0xc0200e1bf0 stack=[0xc0200e00000xc0400e0000]
fatal error: stack overflow
  • 将 nil 函数作为 goroutine 启动 fatal error: go of nil func value
  • goroutines 死锁 fatal error: all goroutines are asleep - deadlock!
  • 线程超过设置的最大限制 fatal error: thread exhaustion
  • 超出可用内存 fatal error: runtime: out of memory

总之 都会报fatal error:xxxxxxxx


拓展&参考:

golang panic和recover 实现原理[1]

Go 学习笔记(19)— 函数(05)[如何触发 panic、触发 panic 延迟执行、panic 和 recover 的关系][2]

Go 语言踩坑记——panic 与 recover[3]


参考资料

[1]

golang panic和recover 实现原理: https://blog.csdn.net/u010853261/article/details/102761955

[2]

Go 学习笔记(19)— 函数(05)[如何触发 panic、触发 panic 延迟执行、panic 和 recover 的关系]: https://blog.csdn.net/wohu1104/article/details/105571916

[3]

Go 语言踩坑记——panic 与 recover: https://xiaomi-info.github.io/2020/01/20/go-trample-panic-recover/

本文由 mdnice 多平台发布

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/31386.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Maven安装与配置

目录 一、Maven简介1.1 概述1.2 作用1.3 仓库 二、安装三、配置3.1 配置环境变量3.2 环境变量测试3.3 配置仓库 一、Maven简介 1.1 概述 Maven是一个开源的项目管理工具,用于构建和管理Java项目,基于项目对象模型(POM)的概念。它…

面试八股文Mysql:(1)事务实现的原理

1. 什么是事务 事务就是一组数据库操作,这些操作是一个atomic(原子性的操作) ,不可分割,要么都执行,要么回滚(rollback)都不执行。这样就避免了某个操作成功某个操作失败&#xff0…

putty使用记录

在官网下载并安装putty 一、SSH 二、FTP open 192.168.1.118 put -r C:\Users\Administrator\Desktop\test /opt/lanren312/test # 上传(文件夹) get -r /opt/lanren312/test C:\Users\Administrator\Desktop\test2 # 下载(文件夹&#xff…

Android Studio实现图形验证码

源代码 源代码MainActivity 效果图32行需要修改,不修改会报错:需要常量表达式,我的代码已修改 点击后 MainActivity import static com.example.graphicverificationcode.RxCaptcha.TYPE.NUMBER;import android.annotation.SuppressLint; …

获取 Android 的 SHA1 值

1、调试版,可以直接在 Android studio 中的 gradle 中查看。也可以用下面方法进行 前提要先确定签名文件所在的路径:调试版默认使用的签名文件是debug.keystore,文件处于 C 盘用户目录下的.android文件夹下。打开命令行工具, 1、…

Uniapp使用腾讯地图并进行标点创建和设置保姆教程

使用Uniapp内置地图 首先我们需要创建一个uniapp项目 首先我们需要创建一个uniapp项目 我们在HBuilder左上角点击文件新建创建一个项目 然后下面这张图的话就是uniapp创建项目过程当中需要注意的一些点和具体的操作 然后我们创建完项目之后进入到项目pages文件夹下&#xff…

web-csrf

目录 CSRF与XSS的区别: get请求 原理: pikachu为例 post请求 pikachu为例 CSRF与XSS的区别: CSRF是借用户的权限完成攻击,攻击者并没有拿到用户的权限,而XSS是直接盗取到了用户的权限 get请求 原理:…

新法!《个人信息保护合规审计管理办法(征求意见稿)》解读

8月3日,依据《中华人民共和国个人信息保护法》等法律法规,国家互联网信息办公室起草了《个人信息保护合规审计管理办法(征求意见稿)》(下文简称“办法”),并向社会公开征求意见。 据悉&#xff…

交互流程图设计软件都有哪些?

交互流程图是设计行业信息流、观点流或组件流的图形代表。但是市场上应该如何选择各种交互流程图软件呢?如何使用高质量的交互流程图软件来绘制高端氛围的高档流程图?今天,小边给您带来了十个超级实用的交互流程图软件,我希望能帮…

竞赛项目 疫情数据分析与3D可视化 - python 大数据

文章目录 0 前言1 课题背景2 实现效果3 设计原理4 部分代码5 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 大数据全国疫情数据分析与3D可视化 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐&#xff0…

【位操作符的几种题型】

位操作符的几种题型 目录 题型一:寻找“单身狗”。 题型二:计算一个数在二进制中1的个数 题型三:不允许创建临时变量,交换两个整数的内容 题型一:寻找“单身狗”。 1.1题目解析 在一个整型数组中,只有…

opencv基础57-模板匹配cv2.matchTemplate()->(目标检测、图像识别、特征提取)

OpenCV 提供了模板匹配(Template Matching)的功能,它允许你在图像中寻找特定模板(小图像)在目标图像中的匹配位置。模板匹配在计算机视觉中用于目标检测、图像识别、特征提取等领域。 以下是 OpenCV 中使用模板匹配的基…

ClickHouse(十三):Clickhouse MergeTree系列表引擎 - ReplicingMergeTree

进入正文前,感谢宝子们订阅专题、点赞、评论、收藏!关注IT贫道,获取高质量博客内容! 🏡个人主页:含各种IT体系技术,IT贫道_Apache Doris,大数据OLAP体系技术栈,Kerberos安全认证-CSDN博客 &…

Nginx反向代理配置+负载均衡集群部署

文章目录 负载均衡反向代理基础环境部署:什么是代理实验环境图流量过程 环境部署准备两台Web服务器安装Nginx准备页面内容添加主机名 代理服务器配置 修改windos hosts文件测试:终端浏览器 负载均衡反向代理基础环境部署: 什么是代理 正向代…

爬虫学习记录(持续更新)

一、问题记录 1.使用webdriver报错AttributeError: str object has no attribute capabilities 解决:目前使用的selenium版本是4.11.2,可以不必设置driver.exe的路径,selenium可以自己处理浏览器和驱动程序,因此,使用…

八月组队学习来了!

Datawhale学习 联合主办:Datawhale,人民邮电出版社 本期学习由Datawhale和人民邮电出版社异步社区联合发起,学习大纲如下(文末整理了这次学习的所有资料): 参与学习 ▶ 活动时间:学习活动 8月1…

二叉树(4)------收尾

1)最大二叉树 654. 最大二叉树 - 力扣(LeetCode) 题目解析: 1)首先我们找到了整个数组中最大的元素作为我们的根节点,然后再从左区间中找到最大的元素作为当前根节点的左子树,然后再从右区间里面找到最大的元素作为根节点的右子树…

直接在html中引入Vue.js的cdn来实现一个简单的博客

摘要 其实建立一个博客系统是非常简单的&#xff0c;有很多开源的程序&#xff0c;如果你不喜欢博客系统&#xff0c;也可以自己开发&#xff0c;也可以自己简单做一个。我这次就是用Vue.js和php做后端服务实现一个简单的博客。 界面 代码结构 代码 index.html <!DOCTYP…

maven的入门使用

maven的入门使用 1.Maven&#xff08;Maven Apache&#xff09;是一个流行的项目构建和管理工具&#xff0c;2.项目结构和POM文件&#xff1a;3.POM文件&#xff08;Project Object Model&#xff09;4.依赖管理&#xff1a; 在POM文件中5.生命周期和构建过程1.前言2.插件系统3…

uni-app使用vue语法进行开发注意事项

目录 uni-app 项目目录结构 生命周期 路由 路由跳转 页面栈 条件编译 文本渲染 样式渲染 条件渲染 遍历渲染 事件处理 事件修饰符 uni-app 项目目录结构 组件/标签 使用&#xff08;类似&#xff09;小程序 语法/结构 使用vue 具体项目目录如下&#xff1a; 生命…