Golang 入门系列(十四)defer, panic和recover用法
以前讲过golang 的基本语法。但是,只是讲了一些基础的语法,感兴趣的可以看看以前的文章,https://www.cnblogs.com/zhangweizhong/category/1275863.html,前段时间有人问我defer,recover的用法。所以,还是统一的总结一下相关的关键字吧。
一. defer 用法
defer的特性: 在函数返回之前, 调用defer函数的操作, 简化函数的清理工作.
在初接触到go时, 就被defer吸引住了,但是在使用defer关键字的时候,还是得注意这些:
1. 在defer表达式确定的时候,defer修饰的函数(后面统称为defered函数)的参数也就确定了
package main import (
"fmt"
) func main() {
g()
} func g() {
i := 0
defer fmt.Println(i)
i++
return
}
-------output-------
0
2. 函数内可以有多个defered函数,但是这些defered函数在函数返回时遵守后进先出的原则
package main
import "fmt"
func main() {
g()
}
func g() {
for i := 0; i<4; i++ {
defer fmt.Println(i)
}
}
-------output-------
3
2
1
0
3. 函数命名的返回值跟defered函数一起使用
函数的返回值有可能被defer更改,本质原因是return xxx语句并不是一条原子指令,执行过程是: 保存返回值(若有)-->执行defer(若有)-->执行return跳转。
func f() (result int) {
defer func() {
result++
}()
return
}
func g() (r int) {
t :=
defer func() {
t = t +
}()
return t
}
func h() (r int) {
defer func(r int) {
r = r +
}(r)
return
}
-------output-------
0
对于defered函数跟函数命名返回值一块使用的情况, 当无法判断返回值的时候, 需要对函数进行变形.
func f(result int) {
result = 0
func () {
result++
}()
return
}
-------output-------
1
func g() (r int) {
t :=
r = t
func () {
t = t +
}
return
}
-------output-------
5
func h() (r int) {
r =
func (r int) {
r = r +
}(r)
return
}
-------output-------
1
在func(r int) {...}中,由于r是以值传递的方式进行的, 所以r的值不会改变。
注意:
1. 申请资源后最好立即使用defer关闭资源。
二. panic用法
panic用法挺简单的, 其实就是throw exception。
panic是golang的内建函数,panic会中断函数F的正常执行流程, 从F函数中跳出来, 跳回到F函数的调用者. 对于调用者来说, F看起来就是一个panic, 所以调用者会继续向上跳出, 直到当前goroutine返回. 在跳出的过程中, 进程会保持这个函数栈. 当goroutine退出时, 程序会crash。
要注意的是, F函数中的defered函数会正常执行, 按照上面defer的规则。
同时引起panic除了我们主动调用panic之外, 其他的任何运行时错误, 例如数组越界都会造成panic
看下面一个例子
package main import (
"fmt"
) func main() {
test()
} func test() {
defer func() { fmt.Println("打印前") }()
defer func() { fmt.Println("打印中") }()
defer func() { fmt.Println("打印后") }()
panic("触发异常")
fmt.Println("test")
}
-------output-------
打印后
打印中
打印前
panic: 触发异常 goroutine [running]:
main.test()
D:/Go_Path/go/src/logDemo/main.go: +0x98
main.main() D:/Go_Path/go/src/logDemo/main.go: +0x27
exit status
三. recover 用法
recover也是golang的一个内建函数, 其实就是try catch。
不过需要注意的是:
1. recover如果想起作用的话, 必须在defered函数中使用。
2. 在正常函数执行过程中,调用recover没有任何作用, 他会返回nil。如这样:fmt.Println(recover()) 。
3. 如果当前的goroutine panic了,那么recover将会捕获这个panic的值,并且让程序正常执行下去。不会让程序crash。
func main() {
fmt.Println("c")
defer func() { // 必须要先声明defer,否则不能捕获到panic异常
fmt.Println("d")
if err := recover(); err != nil {
fmt.Println(err) // 这里的err其实就是panic传入的内容
}
fmt.Println("e")
}()
f() //开始调用f
fmt.Println("f") //这里开始下面代码不会再执行
}
func f() {
fmt.Println("a")
panic("异常信息")
fmt.Println("b") //这里开始下面代码不会再执行
}
-------output-------
c
a
d
异常信息
e
参考链接
1. defer关键字
2. Golang中defer、return、返回值之间执行顺序的坑
Golang 入门系列(十四)defer, panic和recover用法的更多相关文章
- Golang 入门系列(十) mysql数据库的使用
之前,已经讲过一些Golang的基础的东西,感兴趣的可以看看以前的文章,https://www.cnblogs.com/zhangweizhong/category/1275863.html, 今天简 ...
- Golang 入门系列(四)如何理解interface接口
前面讲了很多Go 语言的基础知识,包括go环境的安装,go语言的语法等,感兴趣的朋友,可以先看看之前的文章.https://www.cnblogs.com/zhangweizhong/category ...
- GOLANG错误处理最佳方案errors wrap, Defer, Panic, and Recover
Simple error handling primitives: https://github.com/pkg/errors Defer, Panic, and Recover: ...
- 无废话ExtJs 入门教程十四[文本编辑器:Editor]
无废话ExtJs 入门教程十四[文本编辑器:Editor] extjs技术交流,欢迎加群(201926085) ExtJs自带的编辑器没有图片上传的功能,大部分时候能够满足我们的需要. 但有时候这个功 ...
- Bootstrap入门(十四)组件8:媒体对象
Bootstrap入门(十四)组件8:媒体对象 这是一个抽象的样式,用以构建不同类型的组件,这些组件都具有在文本内容的左或右侧对齐的图片(就像博客评论或 Twitter 消息等). 1.基本样式 2. ...
- MyBatis基础入门《十四》ResultMap子元素(association )
MyBatis基础入门<十四>ResultMap子元素(association ) 1. id: >> 一般对应数据库中改行的主键ID,设置此项可以提高Mybatis的性能 2 ...
- struts2官方 中文教程 系列十四:主题Theme
介绍 当您使用一个Struts 2标签时,例如 <s:select ..../> 在您的web页面中,Struts 2框架会生成HTML,它会显示外观并控制select控件的布局.样式和 ...
- RabbitMQ入门教程(十四):RabbitMQ单机集群搭建
原文:RabbitMQ入门教程(十四):RabbitMQ单机集群搭建 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://b ...
- golang 自学系列(四)——debug for vscode
golang 自学系列(四)--(调试)VSCode For Debug 这里如何装 vscode 我就不说了 这里如何在 vscode 正常写代码我也不说了 在能正常用 vscode 写 go 语言 ...
随机推荐
- python3之递归实例
一.利用递归求: 1+2+3+4+5...+n的前n项和 def recursion_sum_1(n): #当n = 1:和为1 #否则,n的和等同于 n + (n -1) if n == 1: re ...
- css三大特效之优先级
1.什么是优先级作用:当多个选择器选中同一个标签,并且给同一个标签设置相同的属性时,如何层叠就由优先级来确定
- ubuntu 1806 添加 kali 源
最近需要使用 kali 源安装一些软件: 配置 sources.list,根据如下链接:http://mirrors.ustc.edu.cn/help/kali.html 获取 公钥:apt-key ...
- Streams:深入理解Redis5.0新特性
概述 相较于Redis4.0,Redis5.0增加了很多新的特性,而streams是其中最重要的特性之一.streams是redis 的一种基本数据结构,它是一个新的强大的支持多播的可持久化的消息队列 ...
- Android Binder机制介绍
做过Android开发的同学可能有些体会,入门初期,工作内容主要是实现各式各样的UI界面,以及实现应用的业务逻辑.在这个阶段,我们会逐渐熟悉View系统,逐渐学会实现各种各样的界面以及动画效果.再往后 ...
- python函数-参数
python函数-参数 实验室 # 演示形参是可变类型 def register(name, hobby, hobby_list=[]): hobby_list.append(hobby) print ...
- tp5引用第三方类vendor或extend(多种方法)
extend 方法一:命名空间引入 我们只需要把自己的类库包目录放入EXTEND_PATH目录(默认为extend,可配置),就可以自动注册对应的命名空间,例如: 我们在extend目录下面新增一个l ...
- 外键(foreign key)的使用及其优缺点
如果公共关键字在一个关系中是主关键字,那么这个公共关键字被称为另一个关系的外键.由此可见,外键表示了两个关系之间的相关联系.以另一个关系的外键作主关键字的表被称为主表,具有此外键的表被称为主表的从表. ...
- 自动列表排序.html
li:before { content: counter(chapter) ". "; counter-increment: chapter; font-weight: bold; ...
- Python如何爬取实时变化的WebSocket数据
一.前言 作为一名爬虫工程师,在工作中常常会遇到爬取实时数据的需求,比如体育赛事实时数据.股市实时数据或币圈实时变化的数据.如下图: Web 领域中,用于实现数据'实时'更新的手段有轮询和 WebSo ...