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的异常处理机 ...
随机推荐
- JAVA使用IDEA本地调试服务的代码
然后将启动参数的 jdwp=transport=dt_socket,server=y,suspend=n,address=8086 放到服务器上 在执行jar包的命令加入这个 例如 java -jar ...
- JAVA调用WebService接口(以调用第三方天气接口为例)
天气接口地址:http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl 1.打开项目文件目录路径文件夹,在当前文件夹打开cmd, ...
- ByteBuddy代码生成技术
简介 如官网所说Byte Buddy 是一个代码生成和操作库,用于在Java应用程序运行时创建和修改Java类,而无需编译器的帮助.除了Java类库附带的代码生成实用程序外,Byte Buddy还允许 ...
- 【LeetCode】153. Find Minimum in Rotated Sorted Array 解题报告(Python)
[LeetCode]153. Find Minimum in Rotated Sorted Array 解题报告(Python) 标签: LeetCode 题目地址:https://leetcode. ...
- Pikachu漏洞练习-SQL-inject(四)
- AWS 15 年(1):从 Serverful 到 Serverless
2006年,AWS发布了其第一个Serverless存储服务S3和第一个Serverful计算服务EC2,这也是AWS正式发布的前两个服务,开启了云计算波澜壮阔的旅程.2014年,AWS发布了业界第一 ...
- 【C++】关于new分配空间
1如果不使用new,则在函数结束时内存被回收,指针变成野指针 #include <iostream> using namespace std; struct Node { int val; ...
- Mysql数据库体系
Mysql数据库体系如下(手绘): 描述: 1.DBMS:database system management是数据库管理软件,平时我们使用的数据库的全称,是C/S架构(client/server)工 ...
- opencv学习(六)——图像基本操作
图像基本操作 一.访问和修改像素值 先来理解一下,图像与一般的矩阵或张量有何不同(不考虑图像的格式,元数据等信息).首先,一张图像有自己的属性,宽,高,通道数.其中宽和高是我们肉眼可见的属性,而通道数 ...
- MySQL数据库基础(2)表结构管理
目录 一.关系模型与数据表 二.MySQL数据类型 三.数据完整性约束 四.参照完整性约束 一.关系模型与数据表 概念 ①关系模型:是由若干个关系模式组成的集合,关系模式的实例称为关系,每个关系实际上 ...