golang中的异常处理
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
*
golang中的异常处理的更多相关文章
- Golang错误和异常处理的正确姿势
Golang错误和异常处理的正确姿势 错误和异常是两个不同的概念,非常容易混淆.很多程序员习惯将一切非正常情况都看做错误,而不区分错误和异常,即使程序中可能有异常抛出,也将异常及时捕获并转换成错误.从 ...
- Golang中的自动伸缩和自防御设计
Raygun服务由许多活动组件构成,每个组件用于特定的任务.其中一个模块是用Golang编写的,负责对iOS崩溃报告进行处理.简而言之,它接受本机iOS崩溃报告,查找相关的dSYM文件,并生成开发者可 ...
- 优雅处理Golang中的异常
我们在使用Golang时,不可避免会遇到异常情况的处理,与Java.Python等语言不同的是,Go中并没有try...catch...这样的语句块,我们知道在Java中使用try...catch.. ...
- 【repost】JS中的异常处理方法分享
我们在编写js过程中,难免会遇到一些代码错误问题,需要找出来,有些时候怕因为js问题导致用户体验差,这里给出一些解决方法 js容错语句,就是js出错也不提示错误(防止浏览器右下角有个黄色的三角符号,要 ...
- golang中的race检测
golang中的race检测 由于golang中的go是非常方便的,加上函数又非常容易隐藏go. 所以很多时候,当我们写出一个程序的时候,我们并不知道这个程序在并发情况下会不会出现什么问题. 所以在本 ...
- 第65课 C++中的异常处理(下)
1. C++中的异常处理 (1)catch语句块可以抛出异常 ①catch中获捕的异常可以被重新抛出 ②抛出的异常需要外层的try-catch块来捕获 ③catch(…)块中抛异常的方法是throw; ...
- Swift基础--Swift中的异常处理
Swift中的异常处理 OC中的异常处理:方法的参数要求传入一个error指针地址,方法执行完后,如果有错误,内部会给error赋值 Swift中的异常处理:有throws的方法,就要try起来,然后 ...
- ASP.NET Web API 中的异常处理(转载)
转载地址:ASP.NET Web API 中的异常处理
- Struts2中的异常处理
因为在Action的execute方法声明时就抛出了Exception异常,所以我们无需再execute方法中捕捉异常,仅需在struts.xml 中配置异常处理. 为了使用Struts2的异常处理机 ...
随机推荐
- npm ERR! Error: EPERM: operation not permitted
转载于:https://blog.csdn.net/qq_36772866/article/details/86934950 win10 在npm install时报错 解决方案 删除node-mou ...
- 使用Nginx配置资源目录展示下载
nginx配置文件 server { listen 8080; server_name localhost; charset utf-8; location /download { #下载的资源目录 ...
- 【九度OJ】题目1199:找位置 解题报告
[九度OJ]题目1199:找位置 解题报告 标签(空格分隔): 九度OJ http://ac.jobdu.com/problem.php?pid=1199 题目描述: 对给定的一个字符串,找出有重复的 ...
- 【LeetCode】205. Isomorphic Strings 解题报告(Java & Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 字典保存位置 字典保存映射 日期 题目地址:http ...
- Anniversary party(hdu1520)
Anniversary party Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others ...
- 海康威视摄像机Java SDK拉流(二)开启关闭实时预览
本篇介绍海康威视摄像机通过SDK开启关闭实时预览接口 下篇介绍实时预览的回调函数及解码库 测试环境: 系统:Centos 7 SDK:设备网络SDK Linux64 实时预览模块流程: 图中虚线框部分 ...
- [OpenCV]基于特征匹配的实时平面目标检测算法
一直想基于传统图像匹配方式做一个融合Demo,也算是对上个阶段学习的一个总结. 由此,便采购了一个摄像头,在此基础上做了实时检测平面目标的特征匹配算法. 代码如下: # coding: utf-8 ' ...
- 编写Java程序,定义士兵类(Soldiers)并初始化5个士兵对象。
返回本章节 返回作业目录 需求说明: 创建士兵类(Soldiers),定义有一个String类型参数name,代表士兵的姓名,两个int类型变量x和y,分别表示士兵所在的坐标位置,x代表横坐标,y代表 ...
- 从零开始学springboot-2.配置项目
### 配置项目 #### 将application.properties改名为application.yml #### 在resources文件夹中(和上面那个配置文件同一路径下)新建一个文件app ...
- Java 字符与字符串
字符 // 定义字符 char c1 = 'a'; char c2 = '1'; char c3 = '中'; // 自动装箱 Character c = c1; // 自动拆箱 c1 = c; // ...