15、异常处理

异常处理

​ Go的设计者认为其它语言异常处理太过消耗资源,且设计和处理复杂,导致使用者不能很好的处理错误,甚至觉得异常和错误处理起来麻烦而忽视、忽略掉,从而导致程序崩溃。

​ 为了解决这些问题,Go将错误处理设计的非常简单

  • 函数调用,返回值可以返回多值,一般最后一个值可以是error接口类型的值
    • 如果函数调用产生错误,则这个值是一个error接口类型的错误
    • 如果函数调用成功,则该值是nil
  • 检查函数返回值中的错误是否是nil,如果不是nil,进行必要的错误处理

error是Go中声明的接口类型

type error interface {Error() string
}
//已经写入到go的源码中了

所有实现 Error() string 签名的方法,都可以实现错误接口。用Error()方法返回错误的具体描述。

自定义error

package mainimport "fmt"// 定义一个实现了error接口的自定义错误类型 errorString
type errorString struct {s string
}// 实现 errorString 的 Error 方法,使其满足 error 接口
func (e *errorString) Error() string {return e.s
}
// New 函数用于创建并返回一个新的 errorString 实例,接受一个字符串参数作为错误信息
func New(text string) error {return &errorString{text}
}func main() {// 创建一个 errorString 类型的变量 e,并初始化其值为 "错误理由1"var e = errorString{"错误理由1"}// 打印 e 的值、通过 Error 方法获取错误信息、e 的地址以及通过指针调用 Error 方法获取错误信息fmt.Println(e, e.Error(), &e, (&e).Error())// 使用 New 函数创建一个错误,错误信息为 "错误理由2"var err = New("错误理由2")// 打印通过 Error 方法获取的错误信息fmt.Println(err.Error())  //e和err的区别
}在这个程序中,通过定义一个实现了 error 接口的自定义类型 errorString,并在其中实现了 Error 方法,使其可以用作错误类型。然后通过 New 函数创建了两个错误实例,打印访问这些错误实例的错误信息。e 变量:
e 是直接创建的 errorString 类型的变量,其值为 errorString{"错误理由1"}。
errorString 是一个自定义的类型,实现了 error 接口。它包含一个字符串字段 s 和一个实现 Error 方法的函数。
因此,e 的类型是 errorString,但由于实现了 error 接口,可以被赋值给 error 类型的变量。err 变量:
err 是通过 New 函数创建的,该函数返回一个 error 接口类型的指针,指向一个 errorString 类型的实例。其值为 &errorString{"错误理由2"}。
因为 New 函数返回的是 error 接口类型,所以 err 的类型是 error 接口。
虽然底层实现是 errorString 类型,但通过 error 接口,只能访问 error 接口定义的方法,即 Error 方法。
总体来说,e 和 err 都代表实现了 error 接口的错误实例,但 e 是直接的 errorString 类型的实例,而 err 是通过 New 函数返回的 error 接口类型的指针,指向 errorString 类型的实例。
package mainimport ("errors""fmt"
)var ErrDivisionByZero = errors.New("division by zero") // 构造一个错误实例,因为在go的源码中已经写好了函数func New(text string) error {return &errorString{text}}func div(a, b int) (int, error) {if b == 0 {return 0, ErrDivisionByZero}return a / b, nil
}
func main() {if r, err := div(5, 0); err != nil {fmt.Println(err.Error())} else {fmt.Println(r)}
}division by zeroErrDivisionByZero 是一个全局变量,它是通过errors.New函数创建的一个错误实例,表示除零错误。div 函数用于执行除法操作,如果除数为零,则返回 ErrDivisionByZero 错误;否则返回计算结果和 nil 表示没有错误。在 main 函数中,调用 div 函数并根据返回的错误信息进行相应的处理,如果发生除零错误,则打印错误信息,否则打印计算结果。

panic

​ panic是不好的,因为它发生时,往往会造成程序崩溃、服务终止等后果,所以没人希望它发生。但是,如果在错误发生时,不及时panic而终止程序运行,继续运行程序恐怕造成更大的损失,付出更加惨痛的代价。所以,有时候,panic导致的程序崩溃实际上可以及时止损,只能两害相权取其轻。

​ panic虽然不好,体验很差,但也是万不得已,可以马上暴露问题,及时发现和纠正问题。

panic产生

  • runtime运行时错误导致抛出panic,比如数组越界、除零
  • 主动手动调用panic(reason),这个reason可以是任意类型

panic执行

  • 逆序执行当前已经注册过的goroutine的defer链(recover从这里介入)
  • 打印错误信息和调用堆栈
  • 调用exit(2)结束整个进程
package mainimport "fmt"func div(a, b int) int {defer fmt.Println(1, "start")defer fmt.Println(2, a, b)r := a / bfmt.Println(3, "end")return r
}func main() {fmt.Println(div(5, 0))
}运行后程序崩溃,因为除零异常,输入如下
2 5 0
1 start
panic: runtime error: integer divide by zerogoroutine 1 [running]:
main.div(0x5, 0x0)f:/goprpject/test1/main.go:8 +0x230
main.main()f:/goprpject/test1/main.go:14 +0x25
exit status 2这是因为在r := a/b这一行已经panic了,所以后面不执行了,则defer从下往上,输出

recover

​ recover即恢复,defer和recover结合起来,在defer中调用recover来实现对错误的捕获和恢复,让代码在发生panic后通过处理能够继续运行。类似其它语言中try/catch。

package mainimport ("errors""fmt""runtime"
)// 创建一个全局变量 ErrDivisionByZero,表示除零异常
var ErrDivisionByZero = errors.New("除零异常")// 定义一个除法函数,接受两个整数参数,执行除法操作,同时可能会引发panic异常
func div(a, b int) int {// 使用defer延迟执行函数,用于处理panic异常defer func() {// 使用recover捕获panic异常,并在defer中进行处理err := recover()fmt.Printf("1 %+v, %[1]T\n", err)}()// 在defer中输出"start"defer fmt.Println("start")// 在defer中输出a和b的值defer fmt.Println(a, b)// 在defer中进行处理panic异常的代码块defer func() {// 再次使用recover捕获panic异常err := recover()fmt.Printf("2 %+v, %[1]T\n", err)// 使用类型断言判断panic异常的类型,并根据类型进行不同的处理switch v := err.(type) {case runtime.Error:// 判断是否为runtime.Error类型,如果是,输出具体的原因fmt.Printf("原因:%T, %#[1]v\n", v)case []int:// 判断是否为切片类型,如果是,输出"原因:切片"fmt.Println("原因:切片")}fmt.Println("离开recover处理")}()// 执行正常的除法操作r := a / b// 引发panic异常,同时传递一个切片作为panic的值panic([]int{1, 3, 5})// 这里的代码不会被执行,因为上面的panic会导致函数中断fmt.Println("end")// 返回计算结果return r
}func main() {// 调用除法函数,可能引发panic异常fmt.Println(div(5, 0), "!!!")// 在主函数中输出"main exit"fmt.Println("main exit")
}2 runtime error: integer divide by zero, runtime.errorString
原因:runtime.errorString, "integer divide by zero"
离开recover处理
5 0
start
1 <nil>, <nil>
0 !!!
main exit

​ 上例中,一旦在某函数中panic,当前函数panic之后的语句将不再执行,开始执行defer。如果在defer中错误被recover后,就相当于当前函数产生的错误得到了处理。当前函数执行完defer,当前函数退出执行,程序还可以从当前函数之后继续执行。

​ 可以观察到panic和recover有如下:

  • 有panic,一路向外抛出,但没有一处进行recover,也就是说没有地方处理错误,程序崩溃
  • 有painc,有recover来捕获,相当于错误被处理掉了,当前函数defer执行完后,退出当前函数,从当前函数之后继续执行

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

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

相关文章

Django 分页(表单)

目录 一、手动分页二、分页器分页 一、手动分页 1、概念 页码&#xff1a;很容易理解&#xff0c;就是一本书的页码每页数量&#xff1a;就是一本书中某一页中的内容&#xff08;数据量&#xff0c;比如第二页有15行内容&#xff09;&#xff0c;这 15 就是该页的数据量 每一…

报表生成器FastReport .Net用户指南:带图表的报告(图表编辑器)

FastReport .Net是一款全功能的Windows Forms、ASP.NET和MVC报表分析解决方案&#xff0c;使用FastReport .NET可以创建独立于应用程序的.NET报表&#xff0c;同时FastReport .Net支持中文、英语等14种语言&#xff0c;可以让你的产品保证真正的国际性。 FastReport.NET官方版…

基于SSM框架的餐馆点餐系统的设计论文

基于SSM框架的餐馆点餐系统的设计 摘要 当下&#xff0c;正处于信息化的时代&#xff0c;许多行业顺应时代的变化&#xff0c;结合使用计算机技术向数字化、信息化建设迈进。传统的餐馆点餐信息管理模式&#xff0c;采用人工登记的方式保存相关数据&#xff0c;这种以人力为主…

八大算法排序@计数排序(C语言版本)

目录 计数排序概念算法思想算法步骤代码实现时间复杂度空间复杂度特性总结 计数排序 概念 计数排序&#xff08;Counting Sort&#xff09;是一种线性时间复杂度的排序算法&#xff0c;适用于排序一定范围内的整数数组。它利用了输入序列的数值范围来确定每个元素在输出序列中…

【AIGC摄影构图prompt】与重不同的绘制效果,解构主义+优美连拍提示效果

提取关键词构图&#xff1a; 激进解构主义 在prompt中&#xff0c;激进解构主义的画面效果可能是一种颠覆传统和权威的视觉呈现。这种画面可能以一种极端或激烈的方式表达对现有社会结构和观念体系的批判和质疑。 具体来说&#xff0c;这种画面效果可能包括&#xff1a; 破…

怎样使用Halcon控制海康相机实时读取图像

参考收藏halcon连接海康威视相机_halcon连接海康相机-CSDN博客

德思特方案 | 易用、高效、可靠!高精度组合定位系统P-Box测试解决方案

来源&#xff1a;德思特测量测试 德思特方案 | 易用、高效、可靠&#xff01;高精度组合定位系统P-Box测试解决方案 原文链接&#xff1a;https://mp.weixin.qq.com/s/VLlCAT78jQWcc8DeWlRJyw 欢迎关注虹科&#xff0c;为您提供最新资讯&#xff01; 简介 TCU&#xff08;Te…

linux搭建git仓库

git安装与配置 # git安装 yum install -y git# git配置(以下为root用户下配置) # 添加git组 groupadd git# 添加账号、密码(账号zdtest可根据自己需求修改) useradd zdtest -g git passwd zdtest创建远程仓库(linux端) 创建个人文件夹 mkdir -p /home/data/zdtestcd /home/d…

k8s的陈述式管理

k8s的陈述式管理&#xff1a; 所谓的陈述式管离也就是命令行工具 优点&#xff1a;90%以上都可以满足 对资源的增删查比较方便&#xff0c;对改不是很友好 缺点&#xff1a;命令比较冗长&#xff0c;复杂&#xff0c;难记 声明式&#xff1a; k8s当中的YAML文件来实现资源管…

零[0],序,halcon函数区分

1&#xff0c;dev_**&#xff0c;系统/窗口相关算子 halcon形式 dev_clear_obj //从Halcon中删除一个图标物体 dev_clear_window //清除活动窗体 dev_close_inspect_ctrl //关闭控制变量检…

94 使用快慢指针把有序链表转换为二叉搜索树

问题描述&#xff1a;给定一个单链表&#xff0c;其中的元素按升序排列&#xff0c;将其转换为高度平衡的二叉搜索树。在本题中&#xff0c;一个高度平衡二叉搜索树是指一个二叉树中每个节点的左右两个子树的高度差绝对值不超过1. 快慢指针解决&#xff1a;二叉搜索树的特点是…

开源MIT协议软件 - ChatGPT Admin Web

ChatGPT Admin Web 在团队和组织内共享使用人工智能的一站式解决方案。 ​编辑 ​编辑 ​编辑 CAW 是一个自托管网络应用程序&#xff0c;提供开箱即用的用户管理&#xff0c;包括后台界面以及可配置的支付计划和相关支付界面。 GitHub Sponsor / 爱发电 功能 Features …

职场干货!谈谈AI时代必备的产品设计技能

生成式AI技术在2023年的快速进步&#xff0c;让各行各业都加速进入了AI时代。作为科技圈活跃了一整年的绝对爆点&#xff0c;AI似乎真的越来越靠谱了&#xff0c;“所有产品都值得用AI重做一遍”的理念正在走入现实。在这篇文章中&#xff0c;笔者将探讨产品设计行业的从业者们…

瞬态抑制二极管(TVS)的注意事项与布局布线?|深圳比创达电子

一、瞬态抑制二极管(TVS)的注意事项 工作电压/反向截止电压&#xff08;VRVRWM&#xff09;此参数不需要降额&#xff0c;保证大于等于工作电路最大工作电压即可&#xff0c;越接近越好。该参数为TVS的固有参数。VBR是TVS固有参数&#xff0c;与外界冲击波形无关。 被保护器件…

Ribbon相关面试及答案(2024)

1、Ribbon是什么&#xff0c;它在微服务架构中扮演什么角色&#xff1f; Ribbon是一个客户端负载均衡器&#xff0c;它在微服务架构中扮演着关键性的角色。Ribbon的设计理念是在客户端进行服务发现和负载均衡&#xff0c;这种方式不同于传统的通过中心化的负载均衡器&#xff…

基于SpringBoot的旅游网站设计

文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于SpringBoot的旅游网站设计,java项目…

论el-menu自定义样式

最终效果: 原始效果: 相关代码: <!-- 菜单 --><div class"button-manage-right"><el-menu:default-active"activeIndex"class"el-menu-demo"mode"horizontal"select"handleSelect"><el-menu-itemv-fo…

转发的原理及代码演示

一、转发的概念 一个Web组件&#xff08;Servlet/JSP&#xff09;将未完成的处理通过容器转交给另外一个Web组件继续处理&#xff0c;转发 的各个组件会共享Request和Response对象。 二、代码演示 1、编写转发界面 创建空工程&#xff0c;在工程中创建javaEE模块 配置中设置…

前端开发_JavaScript基础

JavaScript介绍 JS是一种运行在客户端&#xff08;浏览器&#xff09;的编程语言&#xff0c;实现人机交互效果 作用&#xff1a; 网页特效 (监听用户的一些行为让网页作出对应的反馈) 表单验证 (针对表单数据的合法性进行判断) 数据交互 (获取后台的数据, 渲染到前端) 服…

CSS-6

响应式网页 如何实现响应式网页&#xff1f; 解决方案&#xff1a;方法1. 通过媒体查询的方法media (条件) {html {background-color: green;}}方法2. 使用 Bootstrap 框架方法一 基本使用 <style>/* 屏幕宽度小于等于768&#xff0c;网页背景色是粉色 --- 小于等于 &…