golang中的异常处理
2024-09-07 11:01:36
1. defer是go提供的一种资源处理的方式。defer的用法遵循3个原则在defer表达式被运算的同时,defer函数的参数也会被运算。如下defer的表达式println运算的同时,其入参i也会被运算,结果为初始化值0,故defer调用中会打印“0”
package main import "fmt" func main() {
f()
} func f() {
i := 0
defer fmt.Println("defer one i", i) // defer three i 0
i++
defer fmt.Println("defer two i", i) // defer three i 1
i++
fmt.Println("i", i) // i 2
defer fmt.Println("defer three i", i) // defer three i 2
}
// 输出结果:
/*
i 2
defer three i 2
defer two i 1
defer one i 0
*/
2. defer函数在一个函数return之后遵循后进先出的调用原则,如下打印结果为43210
func b() {
for i := 0; i < 5; i++ {
defer fmt.Print(i) // 打印 43210
}
}
3. defer函数可能会读取并赋值给所在函数的返回值,如下返回值为2
func c() (i int) {
defer func() { i++ }()
return 1
}
针对上述的第三点有如下三种情况:分别返回 1 5 1 5
// defer案例1
func f1() (result int) {
defer func() {
result++
}()
fmt.Println()
return 0
}
/*
等价于
func f1() (result int) {
result = 0 // return语句不是一条原子调用,return xxx其实是赋值+return指令
defer func() {
result++
}()
return // 空的return指令
}
*/ // defer案例2
func f2() (r int) {
t := 5
defer func() {
t = t + 5
}()
return t
}
/*
等价于
func f2() (r int) {
t := 5
r = t // 赋值指令
defer func() { // defer被插入到赋值与返回之间执行,这个例子中返回值r没被修改过
t = t + 5
}()
return // 空的return指令
} */ // defer案例3
func f3() (r int) {
defer func(r int) {
r = r + 5
}(r)
return 1
}
/*
等价于
func f3() (r int) {
r = 1 // 给返回值赋值
defer func(r int) { // 这里改的r是传值传进去的r,不会改变要返回的那个r值
r = r + 5
}(r)
return // 空的return指令
}
*/
// defer案例4
func f4() (r int) {
t := 5
defer func() {
t += 5
}()
r += 3
return t // 返回5
}
/*
func f4() (r int) {
t := 5
defer func() {
t = t + 5
}()
r += 3
r = t
return // 空的return指令 返回5
}
*/
4. panic和recover的使用需要遵循以下原则:
defer 需要放在 panic 之前定义,另外recover只有在 defer 调用的函数中才有效。
recover处理异常后,逻辑并不会恢复到 panic 那个点去,函数跑到 defer 之后的那个点.
多个 defer 会形成 defer 栈,后定义的 defer 语句会被最先调用
package main import (
"fmt"
) func main() {
f()
fmt.Println("end")
} func f() {
defer func() {
// 必须要先声明defer,否则不能捕获到panic异常
fmt.Println("defer start")
if err := recover(); err != nil {
fmt.Println(err) // 这里的err其实就是panic传入的内容,"runtime error: index out of range [3] with length 2"
}
fmt.Println("defer end") }()
for {
fmt.Println("func begin")
a := []string{"a", "b"}
fmt.Println(a[3]) // 越界访问,肯定出现异常
//panic("bug") // 上面已经出现异常了,所以肯定走不到这里了。
fmt.Println("func end") // 不会运行的.
}
}
输出结果:
1 func begin
2 defer start
3 runtime error: index out of range
4 defer end
5 end
参考网址: https://studygolang.com/articles/13630
5. 多个 defer 会形成 defer 栈,后定义的 defer 语句会被最先调用
package main import (
"fmt"
) /*
defer 需要放在 panic 之前定义,另外recover只有在 defer 调用的函数中才有效。
recover处理异常后,逻辑并不会恢复到 panic 那个点去,函数跑到 defer 之后的那个点.
多个 defer 会形成 defer 栈,后定义的 defer 语句会被最先调用
*/ func main() {
f2()
fmt.Println("end")
} func f2() {
// 必须要先声明defer,否则不能捕获到panic异常
defer func() {
fmt.Println("defer 开始了")
if err := recover(); err != nil {
// 这里的err其实就是panic传入的内容,"runtime error: index out of range [3] with length 2"
fmt.Println(err)
}
fmt.Println("defer 结束了")
}()
defer func() {
fmt.Println("defer2 开始了")
if err := recover(); err != nil {
fmt.Println(err)
}
fmt.Println("defer2 结束了")
}()
fmt.Println("func 开始了")
s1 := []string{"18", "我"}
fmt.Println(s1[2]) // 越界访问,肯定出现异常
panic("BUG") // 上面已经出现异常了,所以肯定走不到这里了。
fmt.Println("func 结束了") // 不会运行的.
} // 输出结果
/*
func 开始了
defer2 开始了
runtime error: index out of range [2] with length 2
defer2 结束了
defer 开始了
defer 结束了
en
*
最新文章
- SQL中字符串拼接
- 走向面试之数据库基础:三、SQL进阶之变量、事务、存储过程与触发器
- .NetCore~Linux环境下部署
- 使用Python创建简单的HTTP和FTP服务
- HashSet其实就那么一回事儿之源码浅析
- 通过indexPath找到对应的cell
- [转]查看手机已经记住的WIFI密码
- 如何解决WebkitBrowser使用出错“Failed to initialize activation context”
- oracle 回车、换行符
- sencha touch2 动画问题
- 2.Hashing
- ArcGIS for Android 中MapView的地图背景设置
- js实现数组内元素随机排序
- C#实现 ffmpeg视频转码、播放
- BufferedReaderTest
- JS创建一个数组1.求和 2.求平均值 3.最大值 4.最小值 5.数组逆序 6.数组去重 0.退出
- 给pdf添加导航目录
- Android ListView的item背景色设置以及item点击无响应等相关问题
- 实验3 敏捷开发与XP实践实验报告
- POJ 2498
热门文章
- JS设置网站所有字体变为繁体字
- Linux(Centos)安装maven
- 【LeetCode】1005. Maximize Sum Of Array After K Negations 解题报告(Python)
- 蓝桥杯练习 Day6 题解
- Spring MVC 文件上传、Restful、表单校验框架
- IM2605说明书| InmicroIM2605|IM2605芯片
- 编写Java程序_定义两个方法,实现奇数偶数的判断,并计算和(有参数有返回值方法)
- .NET 微服务——CI/CD(2):自动打包镜像
- 【】JSON语法RFC4627
- Flink sql 之 两阶段聚合与 TwoStageOptimizedAggregateRule(源码分析)