golang defer那些坑
defer以下几个特性,使用时需要关注下。
- 即时的参数传递
- 调用
os.Exit()时defer不会被执行 - defer与return的先后顺序
1.即时的参数传递
定义defer时传入的参数,是作为拷贝传递的。
也就是说,如果原来的变量值发生变化,不会影响传给defer的参数。
例子如下:
package main
import (
"fmt"
)
func main(){
test()
}
func test() {
a := 0
defer func (i int) {
fmt.Println("in defer i:", i)
}(a)
a += 1
fmt.Println("a:", a)
}
输出结果:
a: 1
in defer i: 0
可以看到,即使变量a发生变化,延迟执行时变量的值仍然是0,与定义defer时传入的值一样。
2.调用os.Exit()时defer不会被执行
当发生panic时,defer会被执行,但是当调用os.Exit()方法退出程序时,defer并不会被执行。
package main
import (
"fmt"
"os"
)
func main(){
fmt.Println("main start")
test()
}
func test() () {
defer func () {
fmt.Println("in defer ... ")
}()
os.Exit(0)
}
输出结果:
main start
defer定义的内容没有输出。
3.defer 与 return先后顺序
先来看两个例子:一个是返回匿名变量,一个是返回命名变量。
3.1 返回匿名变量
package main
import (
"fmt"
)
func main(){
i := test()
fmt.Println("main i:", i)
}
func test() int {
a := 0
defer func () {
a = 2
}()
a = 1
return a
}
定义a为0, 接着修改为1,最后在defer中将a修改为2。
在main中返回的值仍然是1.
输出结果:
main i: 1
3.2 返回命名变量
package main
import (
"fmt"
)
func main(){
i := test()
fmt.Println("main i:", i)
}
func test() (a int) {
defer func () {
a = 2
}()
a = 1
return a
}
defer中修改a为2,能够返回给调用方。
输出结果:
main i: 2
实际上,defer 函数的执行既不是在 return 之后也不是在 return 之前,而是 return 语句包含了对 defer 函数的调用,即 return 会被翻译成如下几条伪指令:
保存返回值到栈上(如果是匿名变量,需要定义变量并赋值)
调用defer函数(如果有defer函数,则调用并执行)
调整函数栈
retq指令返回(如果是匿名变量,直接返回新定义的变量,如果是命名变量,直接返回命名变量)
命名变量返回时,不会创建新的变量,所以defer的修改会返回去。
而匿名变量,会创建新的变量,defer中的修改,还是修改原来的变量,所以修改不能返回去。
4.参考
https://juejin.im/post/5b9b4acde51d450e5071d51f
https://my.oschina.net/henrylee2cn/blog/505535
golang defer那些坑的更多相关文章
- Golang中的坑二
Golang中的坑二 for ...range 最近两周用Golang做项目,编写web服务,两周时间写了大概五千行代码(业务代码加单元测试用例代码).用Go的感觉很爽,编码效率高,运行效率也不错,用 ...
- Golang 中的坑 一
Golang 中的坑 短变量声明 Short variable declarations 考虑如下代码: package main import ( "errors" " ...
- Golang的防坑小技巧
Golang的防坑小技巧 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 作为一名小白,在之前没有接触到编程的小伙伴,难免会踩到一些坑,比如说刚刚入门的时候你需要安装环境,学习Gol ...
- golang的defer踩坑汇总
原文链接:http://www.zhoubotong.site/post/50.html defer语句用于延迟函数调用,每次会把一个函数压入栈中,函数返回前再把延迟的函数取出并执行.延迟函数可以有参 ...
- 初学者学习golang可能遇到的坑
我也是个golang初学者,刚入门的话,有些"坑"还是不好发现的.如map只是定义了然后就拿来使用,变量的值覆盖等. 本来打算写一篇的,后面发现有人写的挺不错的,我就把里面的有些坑 ...
- golang defer 延后执行什么
对于golang的defer,我们已经知道,defer定义的语句可以延后到函数返回时执行. 经常用在文件的关闭,锁的释放等场景中.而且defer定义的语句即使遇到panic也会执行.这样,可以执行必要 ...
- 『go成长之路』 defer 作用、典型用法以及多个defer调用顺序,附加defer避坑点,拿来吧你
预习内容 defer 的作用有哪些? 多个 defer 的执行顺序是怎样的? defer,return,函数返回值 三者之间的执行顺序 defer的作用 go中的defer是延迟函数,一般是用于释放资 ...
- golang的哪些坑爷事: package实践
在golang中package是个困惑的概念, 特别是package还可以与folder不同名, 委实让我恶心了一把. 关于golang的package的最佳实践: package is folder ...
- golang defer的使用
defer一般用于在函数结束时执行必要的处理工作.例如,关闭文件描述符,关闭网络连接等等. 函数中可以定义多个defer,执行的时候按照先进后出的顺序. defer定义的语句,即使遇到panic,也会 ...
随机推荐
- 87. Scramble String (Java)
Given a string s1, we may represent it as a binary tree by partitioning it to two non-empty substrin ...
- 利用python3 爬虫 定制版妹子图mzitu爬取
在刚开始学爬虫的时候,用来练手的基础爬虫就是爬取各种妹子图片,前几天同时说了这个,便准备随便写一个...最后发现真是三天不练..什么都记不住了!!所以花了政治一天重新写了一个爬虫程序,并且支持按照时间 ...
- 学习Linux让我进入了知名企业 原
说起我学习Linux的原因是多方面的,大学时我学的是物理学师范专业,有部分计算机课程,但我觉得这些课程没什么实际作用,我自己对计算机比较感兴趣,我利用业余时间学习了很多计算机技术.在大学期间我参加了很 ...
- 变分推断到变分自编码器(VAE)
EM算法 EM算法是含隐变量图模型的常用参数估计方法,通过迭代的方法来最大化边际似然. 带隐变量的贝叶斯网络 给定N 个训练样本D={x(n)},其对数似然函数为: 通过最大化整个训练集的对数边际似然 ...
- Detecting Unstable Periodic Orbits in Chaotic Experimental Data (解析)
原文链接:https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.76.4705 发表在:PRL 1996 ---------------- ...
- mysql向表中某字段前后追加一段字符串 concat(), trim(), ltrim(), rtrim(), repeat()
1.mysql向表中某字段后面追加一段字符串:update table_name set field=CONCAT(field, '分隔符', str);//'分隔符',可以为空,也可以省略updat ...
- Summer training round2 #6 (Training #22)
A:二分答案 如果中位数比目前的大就right=mid-1 else left=mid+1 C!:几何 G:优先队列贪心 #include <bits/stdc++.h> using na ...
- 创建CUDA项目
输出选择X64 .cu文件属性: 常规-项类型:CUDA C/C++ 项目属性: 平台:活动(x64) CUDA C/C++ - Common-Target Machine Platform: 64- ...
- 10个不为人知的 Python 冷知识
转载: 1. 省略号也是对象 ...这是省略号,在Python中,一切皆对象.它也不例外. 在 Python 中,它叫做 Ellipsis . 在 Python 3 中你可以直接写…来得到这玩意. 而 ...
- Vue+NodeJS+ElementUI 的简单示例
演示所使用到的工具:谷歌浏览器.HBuilder.cmd命令窗口.nodejs(自带npm). 1.先使用 vue create 命令创建一个项目,等待创建完成. 2.切换到项目中. 3.使用 vue ...