GoLang中panic与recover函数以及defer语句超详细讲解
作者:鲲鹏飞九万里 发布时间:2024-03-22 09:41:37
一、运行时恐慌panic
panic是一种在运行时抛出来的异常。比如"index of range"。
panic的详情:
package main
import "fmt"
func main() {
oneC := []int{1, 2, 3, 4, 5}
v5 := oneC[5]
fmt.Println(v5)
}
$ go run demo01.go
panic: runtime error: index out of range [5] with length 5
goroutine 1 [running]:
main.main()
/Users/lifei/Documents/workspace/githubRepositoies/gowp/projects/go-core-example/src/article19/q1/demo01.go:7 +0x1b
exit status 2
$
打印信息的第一行,"panic: "右边的内容,正是panic包含的runtime.Error
类型值的字符串表示形式;
“goroutine 1 [running]” 表示有一个id为 1 的 goroutine在此panic被引发的时候正在运行;
这里的ID编号并不重要,是GO语言运行时系统内部给予的一个goroutine编号,我们在程序中无法获取,也无法改变。
再下面是指出哪一行发生错误。“+0x1b”代表 此行代码相对于其所属函数的入口程序计数偏移量, 一般用途不大。
最后的 “exit status 2”,表明我的这个程序是以退出状态码2结束运行的。
在大多操作系统中,只要退出状态码不是0,都意味着程序运行的非正常结束。
二、panic被引发到程序终止经历的过程
某个函数无疑触发了panic:
初始的panic详情会被建立起来,此行代码所属函数的执行随机终止。
控制权立刻转移到上一级;
控制权如此一层层沿着调用栈的反方向传播至顶端,也就是我们编写的最外层函数;
最终,控制权被GO语言运行时系统收回。随后程序崩溃并终止运行;
panic 详情会在控制权传播的过程中,被逐渐地积累和完善,并且,控制权会一级一级地沿着调用栈的反方向传播至顶端。因此,在针对某个 goroutine 的代码执行信息中,调用栈底端的信息会先出现,然后是上一级调用的信息,以此类推,最后才是此调用栈顶端的信息。
三、有意引发一个panic并让panic包含一个值
可以使用panic函数有意地引发一个 panic。
在调用panic函数时,把某个值作为参数传给该函数就可以了。由于panic函数的唯一一个参数是空接口(也就是interface{})类型的,所以从语法上讲,它可以接受任何类型的值。
但是,我们最好传入error类型的错误值,或者其他的可以被有效序列化的值。这里的“有效序列化”指的是,可以更易读地去表示形式转换。
打印错误信息:
对于fmt包下的各种打印函数来说,error类型值的Error方法与其他类型值的String方法是等价的,它们的唯一结果都是string类型的;
如果某个值有可能会被记到日志里,那么就应该为它关联String方法。
四、施加应对panic的保护措施从而避免程序崩溃
联用defer语句和recover函数调用,才能够恢复一个已经发生的 panic。
GO语言的内建函数recover专门用于恢复panic。recover函数无需任何参数,并且会返回一个空接口类型的值。
defer 语句用来延迟执行代码。延迟到该语句所在的函数即将执行结束的那一刻,无论结束执行的原因是什么。
限制:有一些调用表达式是不能出现在这里的,包括:针对 Go 语言内建函数的调用表达式,以及针对unsafe包中的函数的调用表达式。
package main
import (
"errors"
"fmt"
)
func main() {
fmt.Println("Enter function main")
// 延迟func函数的执行,直到main结束
defer func() {
fmt.Println("Enter defer function")
if p := recover(); p != nil {
fmt.Printf("%v\n", p)
}
fmt.Println("Exit defer function")
}()
// 引发painc
panic(errors.New("soming wrong"))
fmt.Println("Exit function main")
}
五、多条defer语句多条defer语句的执行顺序
在同一个函数中,defer函数调用的执行顺序与它们分别所属的defer语句的出现顺序(更严谨地说,是执行顺序)完全相反。
当一个函数即将结束执行时,其中的写在最下边的defer函数调用会最先执行,其次是写在它上边、与它的距离最近的那个defer函数调用,以此类推,最上边的defer函数调用会最后一个执行。
defer语句执行的内幕:
在defer语句每次执行的时候,Go 语言会把它携带的defer函数及其参数值另行存储到一个链表中。
这个链表与该defer语句所属的函数是对应的,并且,它是先进后出(FILO)的,相当于一个栈。
在需要执行某个函数中的defer函数调用的时候,Go 语言会先拿到对应的链表,然后从该链表中一个一个地取出defer函数及其参数值,并逐个执行调用。
package main
import "fmt"
func main() {
defer fmt.Println("first defer")
for i := 0; i < 3; i++ {
defer fmt.Printf("defer in for %d\n", i)
}
defer fmt.Println("last defer")
}
来源:https://blog.csdn.net/hefrankeleyn/article/details/128556143
猜你喜欢
- 今天暴风彬彬要讨论的网站可用 * ,是让你的网站文字链接提高一定的可用性,而且实现起来非常简单,其实这也算是提高用户体验的方法。扩大可点击区
- 如下所示:#coding=utf-8#方式一print('*'*20 + '方式一' + '*
- 在windows+iis服务器上运行asp程序可能会出现数据库无法更新的情况,具体错误信息可能为: 1、Microsoft JET Data
- 在嵌入式、尤其是机器人的python编程中,经常需要实时检测用户的键盘输入来随时控制机器人,这段代码可以帮助我们提取用户输入的字符,并在按下
- 准备篇:1、配置防火墙,开启80端口、3306端口vi /etc/sysconfig/iptables-A INPUT -m state -
- 数据库对于服务端开发人员来说,几乎就是左膀右臂。几乎每一个服务端开发人员都要和数据库打交道。而MySQL又以其开源免费,小巧玲珑,简单易用,
- 如果你不知道原因,不要过于担心,请研究CSS规则并查看这篇文章:使用CSS来修正一切: 20 +常见错误和修复。 如果这些也无效,您可以通过
- 英文文档:class complex([real[, imag]])Return a complex number with the val
- (一).确认删除用法: 1. BtnDel.Attributes.Add("onclick","return
- 用过一段时间的caffe后,对caffe有两点感受:1、速度确实快; 2、 太不灵活了。深度学习技术一直在发展,但是caffe的更新跟不上进
- 值得学习的地方:1.选择合法索引的方式2.数组转图像显示import numpy as npfrom PIL import Image#in
- 建立一个查询,执行下面的语句生成函数fn_GetPy --生成拼音首码 CREATE function fn_GetPy(@str nvar
- ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。E
- modelform是model衍生出来的form .modelform的用法非常死.首先在models.py里创建模型表.所有的form组件
- 多个字段模糊查询, 括号中的下划线是双下划线,双下划线前是字段名,双下划线后可以是icontains或contains,区别是是否大小写敏感
- 本文实例讲述了JS弹出窗口插件zDialog简单用法。分享给大家供大家参考,具体如下:因为没有元素可以显示到Frameset上面去,所以重新
- Ajax 技术改变了大型商业 Web 应用程序的外观,但是许多较小的 Web 站点都不具备足够的资源重新构建完整的用户界面(UI)。Ajax
- 通过Python中的matplotlib绘制百分比堆叠柱状图,并为每一个类别设置不同的填充图案。主要原因是有些论文打印出是黑白色的,不同类别
- 本篇文章主要内容代理类主要功能是将一个类实例的属性访问和控制代理到代码内部另外一个实例类,将想对外公布的属性的访问和控制权交给代理类来操作,
- 1、炫酷星空登录实现代码<!DOCTYPE HTML><html><head><meta http