13.Go 异常

1、宕机

Go语言的类型系统会在编译时捕获很多错误,但有些错误只能在运行时检查,如数组访问越界、空指针引用等,这些运行时错误会引起宕机。

一般而言,当宕机发生时,程序会中断运行,并立即执行在该goroutine(线程)中被延迟的函数(defer机制),随后,程序崩溃并输出日志信息。日志信息包括panic value和函数调用的堆栈跟踪信息,panicvalue通常是某种错误信息。

引发宕机有如下两种情况:

  • 程序主动调用panic()函数。
  • 程序产生运行时错误,由运行时检测并抛出。

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

panic的参数是一个空接口类型interface{},所以,任意类型的变量都可以传递给panic。调用panic的方法非常简单,即panic (xxx)。

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

Go语言可以在程序中手动触发宕机,让程序崩溃,这样开发者可以及时发现错误,同时减少可能的损失。

Go语言程序在宕机时,会将堆栈和goroutine信息输出到控制台,所以,宕机也可以方便地确定发生错误的位置。

func main() {
    panic("crash")
}


当panic()触发的宕机发生时,panic()后面的代码将不会被运行,但是在panic()函数前面已经运行过的defer语句依然会在宕机发生时发生作用:

func main() {
	defer fmt.Println("宕机时要做的事情1...")
	defer fmt.Println("宕机时要做的事情2...")
	panic("crash")
}

2、宕机恢复

无论代码运行错误是由Runtime层抛出的panic崩溃,还是主动触发的panic崩溃,都可以配合defer和recover实现错误的捕捉和恢复,让代码发生崩溃后允许继续运行。

recover()用来捕获panic,阻止panic继续向上传递。recover()函数可以和defer语句一起使用,但recover()函数只有在defer后面的函数体内被直接调用才能捕获panic终止异常,否则会返回nil,异常继续向外传递。

可以有连续多个panic被抛出,连续多个被抛出的场景只能出现在延迟调用中。虽然有多个panic被抛出,但是只有最后一次的panic才能被捕获:

func main() {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println(err)
		}
	}()

	// 只有最后一次的panic调用能够被捕获
	defer func() {
		panic("first defer panic")
	}()

	defer func() {
		panic("second defer panic")
	}()
	panic("main body panic")
}

panic和recover的关系如下:

  • 有panic没recover,程序宕机。
  • 有panic也有recover,程序不会宕机,执行完对应的defer语句后,从宕机点退出当前函数后继续执行。
3、错误与处理

Go语言的错误处理过程如下:

  • 一个可能造成错误的函数,需要返回值中返回一个错误接口,如果调用是成功的,错误接口将返回nil,否则返回错误。
  • 在函数调用后需要检查错误,如果发生错误,则进行必要的错误处理。
a. 错误接口

error是Go语言系统声明的接口类型,语法格式:type error interface {Error() string}

所有符合Error()string格式的方法,都能实现错误接口,Error()方法返回错误的具体描述,使用者可以通过该字符串知道发生了什么错误。

Go语言内置错误接口类型error。任何类型只要实现Error() string方法,都可以传递error接口类型变量。Go语言典型的错误处理方式是将error作为函数最后一个返回值。在调用函数时,通过检测其返回的error值是否为nil来进行错误处理。

b. 自定义错误

返回错误前,需要定义会产生哪些可能的错误,在Go语言中,使用errors包进行错误的定义,格式如下:

var err = errors.New("this is an error")

错误字符串由于相对固定,一般在包作用域声明,应尽量减少在使用时直接使用errors.New返回。

errors 包:Go语言的errors中对New的定义非常简单

// 创建错误对象
func New(text string) error {
	return &errorString{text}
}

// 错误字符串
type errorString struct {
	s string
}

// 返回发生何种错误
func (e *errorString) Error() string {
	return e.s
}
  • 第2行:将errorString结构体实例化,并赋值错误描述的成员。
  • 第7行:声明errorString结构体,拥有一个成员,描述错误内容。
  • 第12行:实现error接口的Error()方法,该方法返回成员中的错误描述。

在代码中使用错误定义——例如:定义一个除法函数,当除数为0时,返回一个预定义的除数为0的错误。

// 定义除数为0的错误
var errDivisionByZero = errors.New("division by zero")

func div(dividend, divisor int) (int, error) {
	// 判断除数为0的情况并返回
	if divisor == 0 {
		return 0, errDivisionByZero
	}
	// 正常计算,返回空错误
	return dividend / divisor, nil
}

func main() {
	fmt.Println(div(1, 0))
}

c. 错误和异常

错误是指发生非期望的已知行为,这里的已知是指错误的类型是预料并定义好的。

异常是指发生非期待的未知行为。这里的未知是指错误的类型不在预先定义的范围内。异常又被称为未捕获的错误(untrapped error)。程序在执行时发生未预先定义的错误,程序编译器和运行时都没有及时将其捕获处理,而是由操作系统进行异常处理。

在Go语言中对于错误提供了两种处理机制:

  • 通过函数返回错误类型的值来处理错误。
  • 通过panic打印程序调用栈,终止程序执行来处理错误。

对错误的处理也有两种方法:

  • 一种是通过返回一个错误类型值来处理错误,
  • 另一种是直接调用panic抛出错误,退出程序。

Go是静态强类型语言,程序的大部分错误是可以在编译器检测到的,但是有些错误行为需要在运行期才能检测出来。此种错误行为将导致程序异常退出。其表现出的行为就和直接调用panic一样:打印出函数调用栈信息,并且终止程序执行。

在实际的编程中,error和panic的使用应该遵循以下原则:

(1)程序发生的错误导致程序不能容错继续执行,此时程序应该主动调用panic或由运行时抛出panic。

(2)程序虽然发生错误,但是程序能够容错继续执行,此时应该使用错误返回值的方式处理错误,或者在可能发生运行时错误的非关键分支上使用recover捕获panic。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

rk3588中编译带有ffmpeg的opencv

有朋友有工程需要,将视频写成mp4,当然最简单的方法当然是使用opencv的命令 cv::VideoWriter writer;bool bRet writer.open("./out.mp4", cv::VideoWriter::fourcc(m, p, 4, v), 15, cv::Size(640, 512), 1); 但是奈何很难编译成功&#xff…

go执行静态二进制文件和执行动态库文件

目的和需求:部分go的核心文件不开源,例如验证,主程序核心逻辑等等 第一个想法,把子程序代码打包成静态文件,然后主程序执行 子程序 package mainimport ("fmt""github.com/gogf/gf/v2/os/gfile"…

云服务器评估迁移时间与测试传输速度

迁移周期主要分为迁移前、迁移过程中、迁移后三部分。迁移周期时长与待迁移服务器的数量和实际数据量成正比,建议您根据实际迁移测试演练进行评估。本文主要介绍迁移过程中这一阶段所需时间的评估方式和传输速度的测试方法。 背景信息 在SMC迁移过程中&#xff0c…

UV打印机磁栅尺的安装

UV打印机磁栅尺的安装方法有以下几个注意事项: 1. 安装基面的选择:磁栅尺需要粘合在平滑的基面上,基面要足够平整且干净,不能有杂质或油污。 2. 粘合剂的选用:磁栅尺的粘合剂需要选用合适的胶水,最好是专门…

maven:在maven中使用tomcat7插件

1、在pom.xml中添加tomcat7插件 <build><!-- Embedded Apache Tomcat required for testing war --><plugin><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><version>2.2</ver…

【JavaFX】JavaFX11开发踩坑记录

文章目录 技术栈踩坑记录 技术栈 JavaFX 11MavenJDK 11 踩坑记录 这些坑对于初学者很容易踩&#xff0c;JavaFX经常会报错空指针异常遇到其中一个问题可能就会消耗好几天的时间。 JavaFX 采用的是MVC架构设计&#xff0c;页面设计使用 fxml文件&#xff1b;业务逻辑采用Con…

前端框架的异步组件(Async Components)

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

pytorch集智-1安装与简单使用

1 安装 1.1 简介 pytorch可用gpu加速&#xff0c;也可以不加速。gpu加速是通过cuda来实现&#xff0c;cuda是nvidia推出的一款运算平台&#xff0c;它可以利用gpu提升运算性能。 所以如果要装带加速的pytorch&#xff0c;需要先装cuda&#xff0c;再装pytorch&#xff0c;如…

【C程序设计】C循环

有的时候&#xff0c;我们可能需要多次执行同一块代码。一般情况下&#xff0c;语句是按顺序执行的&#xff1a;函数中的第一个语句先执行&#xff0c;接着是第二个语句&#xff0c;依此类推。 编程语言提供了更为复杂执行路径的多种控制结构。 循环语句允许我们多次执行一个…

偏导函数公式以及使用 python 计算

偏导函数 偏导函数是多元函数对其中一个变量的偏导数。对于一个多元函数&#xff0c;其输入变量有两个或更多&#xff0c;而偏导函数则表示对其中一个变量的偏导数&#xff0c;将其他变量视为常数。 设有一个具有 n 个自变量的函数 f(,,...,)&#xff0c;则对于其中的某一个自…

OpenHarmony源码转换器—多线程特性转换

本文讨论了如何将多线程的 Java 代码转换为 OpenHarmony ArkTS 代码​ 一、简介 Java 内存共享模型 以下示例伪代码和示意图展示了如何使用内存共享模型解决生产者消费者问题。 生产者消费者与共享内存间交互示意图 为了避免不同生产者或消费者同时访问一块共享内存的容器时…

通信网络(3)——DHCP Snooping

一、简介 前面一节介绍的DAI技术是基于DHCP Snooping绑定表的&#xff0c;因此本篇文章用于介绍何为DHCP Snooping&#xff0c;它是如何生成绑定表的 二、DHCP Snooping诞生背景 由于DHCP报文和ARP报文一样没有认证机制&#xff0c;因此和ARP报文一样&#xff0c;别人给我什…

Java基础-----集合类(四)

文章目录 1. Iterator和ListIterator1.1 简介1.2 常用方法 2. remove方法2.1 比较foreach方式和迭代器方式删除元素2.2 找原因 -- 迭代器删除操作源码 1. Iterator和ListIterator 1.1 简介 1.Iterator 可以遍历List集合&#xff0c;也可以遍历Set集合&#xff1b; ListIterat…

Linux学习(9)——RAID与服务器的常见故障

目录 一、服务器常见故障 1、系统不停重启进入不了系统 2、卡在开机界面右下角有fA B2 H8 3、系统安装不上 4、如何进入服务器的bios 5、一般进入阵列卡的快捷键 6.网络不通 7.硬盘不识别 二、RAID相关知识 1、RAID的概念 2、RAID功能实现 3、RAID实现的方式 三、…

2024年01月数据库流行度最新排名

点击查看最新数据库流行度最新排名&#xff08;每月更新&#xff09; 2024年01月数据库流行度最新排名 TOP DB顶级数据库索引是通过分析在谷歌上搜索数据库名称的频率来创建的 一个数据库被搜索的次数越多&#xff0c;这个数据库就被认为越受欢迎。这是一个领先指标。原始数…

2020年认证杯SPSSPRO杯数学建模C题(第一阶段)抗击疫情,我们能做什么全过程文档及程序

2020年认证杯SPSSPRO杯数学建模 C题 抗击疫情&#xff0c;我们能做什么 原题再现&#xff1a; 2020 年 3 月 12 日&#xff0c;世界卫生组织&#xff08;WHO&#xff09;宣布&#xff0c;席卷全球的冠状病毒引发的病毒性肺炎&#xff08;COVID-19&#xff09;是一种大流行病。…

js中函数动态调用

文章目录 一、场景二、方法2.1、动态函数2.2、eval()函数 三、最后 一、场景 在JS开发中&#xff0c;例如有些场景下&#xff0c;后端要求一个功能要请求不同的接口&#xff0c;但是传参及后续逻辑其实都是一样的&#xff0c;有些同学可能会想到在接口url处统一处理就好&#…

51单片机项目(27)——基于51单片机的智能门窗设计

1.功能设计 使用普中51单片机&#xff0c;门窗有自动模式和手动模式。 手动模式下&#xff0c;LCD1602显示屏上显示“manu mode”&#xff0c;通过红外遥控器&#xff0c;控制门窗的开关。其中&#xff0c;按键0代表开窗&#xff0c;按键1代表关窗。&#xff08;使用风扇模拟门…

【Vue2+3入门到实战】(17)VUE之VueCli脚手架自定认创建项目、ESlint代码规范与修复、 ESlint自动修正插件的使用 详细示例

目录 一、本节内容二、VueCli 自定义创建项目三、ESlint代码规范及手动修复1.JavaScript Standard Style 规范说明2.代码规范错误3.手动修正 四、通过eslint插件来实现自动修正 一、本节内容 VueCli脚手架自定认创建项目ESlint代码规范与修复ESlint自动修正插件 二、VueCli 自…

qt 异常汇总

1. C2338 No Q_OBJECT in the class with the signal (编译源文件 ..\..\qt\labelme-master\src\mainwindow.cpp mainwindow头文件中的类没有Q_OBJECT宏定义&#xff0c;或者其子类或者其他依赖没有Q_OBJECT宏定义。 全部qt类都要写上Q_OBJECT. 2. C2385 对connect的访…