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 语言 ...
随机推荐
- 使用RNN进行imdb影评情感识别--use RNN to sentiment analysis
原创帖子,转载请说明出处 一.RNN神经网络结构 RNN隐藏层神经元的连接方式和普通神经网路的连接方式有一个非常明显的区别,就是同一层的神经元的输出也成为了这一层神经元的输入.当然同一时刻的输出是不可 ...
- websrom编译器
webstorm less环境配置 备注: 安装node后,在命令行输入npm install -g less 即可安装less,打开webstorm setting-Tools-FileWatche ...
- SSM框架整合 详细步骤(备注) 附源码
整合思路 将工程的三层结构中的JavaBean分别使用Spring容器(通过XML方式)进行管理. 整合持久层mapper,包括数据源.会话工程及mapper代理对象的整合: 整合业务层Service ...
- JavaScript笔记六
1.对象(Object) - 对象是JS中的引用数据类型 - 对象是一种复合数据类型,在对象中可以保存多个不同数据类型的属性 - 使用typeof检查一个对象时,会返回object - 创建对象 - ...
- getElementById()
getElementById():方法的用途是寻找一个有着给定id属性值得元素: element = document.getElementById(ID); 这个方法将返回一个有着给定id属性值得元 ...
- java Random类详解
java Random类位于java.util包下,主要用来生成随机数,本文详解介绍了Random类的用法,希望能帮到大家 Random类 (java.util) Random类中实现的随机算法是伪随 ...
- Flask入门学习——自定义一个url转换器
我们知道,flask的url规则是可以添加变量部分的,这个参数变量是写在尖括号里的,比如:/item/<id>/,如果需要指出参数的类型要符合<converter:vai ...
- 【RN - 基础】之TextInput使用简介
TextInput组件允许用户在应用中通过键盘输入文本信息,其使用方法和Text.Image一样简单,实例代码如下: <TextInput placeholder={'请输入用户名'} styl ...
- jenkins System error
背景 在使用WAR包安装jenkins后,启动tomcat,显示启动成功,但最后提示信息如下: 04-Dec-2018 03:28:21.563 WARNING [Computer.threadPoo ...
- nginx代理跨域,根据路径参数改变目标服务器地址
我们都知道nginx是可以做跨域代理的: location ^~ /visited-path/ { proxy_pass http://another-domain/; } 举个例子:假如我们的代理服 ...