Go defer 使用
defer特性:
- 关键字 defer 用于注册延迟调用。
- 这些调用直到 return 前才被执。因此,可以用来做资源清理。
- 多个defer语句,按先进后出的方式执行。
- defer语句中的变量,在defer声明时就决定了。
defer用途:
- 关闭文件句柄
- 锁资源释放
- 数据库连接释放
package mainimport "fmt"func main() {var users [5]struct{}for i := range users {defer fmt.Println(i)}
}
输出:4 3 2 1 0 ,defer 是先进后出
package defer_testimport ("fmt""testing"
)func TestDefer1(t * testing.T) {var users [5]struct{}for i := range users {defer func() { fmt.Println(i) }()}
}
输出结果: 4 4 4 4 4
是否在想一个问题,输出结果不是 4 3 2 1 0 , 由于是闭包用到的变量 i 在执行的时候已经变成了4 , 所以输出全部是 4, 如何正常输出。4 3 2 1 0 ? 不用闭包,换成函数即可。
func TestDefer2(t *testing.T) {var users [5]struct{}for i := range users {defer Print(i)}
}func Print(i int) {fmt.Println(i)
}
函数的输出结果是 : 4 3 2 1 0
再看个结构体的例子
func (t *Users) GetName(){fmt.Println(t.name)
}func TestDefer3(t * testing.T){list := []Users{{"乔峰"}, {"慕容复"},{"欧阳克"}}for _, t := range list {defer t.GetName()}
}
发现没,输出的结果竟然是 欧阳克 欧阳克 欧阳克
不是欧阳克 慕容复 乔峰
如何要输出 : 欧阳克 慕容复 乔峰
写个函数:
type Users struct {name string
}func (t *Users) GetName(){fmt.Println(t.name)
}func GetName(t Users){t.GetName()
}func TestDefer4(t *testing.T) {list := []Users{{"乔峰"}, {"慕容复"},{"欧阳克"}}for _, t := range list {defer GetName(t)}
}
函数输出结果:
欧阳克
慕容复
乔峰
如果不想多写一个函数,输出
欧阳克
慕容复
乔峰
要怎么搞?复制一份即可
type Users struct {name string
}func (t *Users) GetName() {fmt.Println(t.name)
}func TestDefer5(t *testing.T) {list := []Users{{"乔峰"}, {"慕容复"}, {"欧阳克"}}for _, t := range list {t1 := tdefer t1.GetName()}
}
输出结果:
欧阳克
慕容复
乔峰
defer 后面的语句在执行的时候,函数调用的参数会保存起来,复制一份,但是不执行。
多个 defer 注册,采用的是 FILO 先进后出的方式,哪怕函数发生错误, 这些调用依然会被执行。
func users(i int) {defer println("北丐")defer println("南帝")defer func() {println("西毒")println(10 / i) // 异常未被捕获,逐步往外传递,最终终止进程。}()defer println("东邪")
}
func TestDefer6(t *testing.T) {users(0)println("武林高手排行榜,这里不会被输出")
}
defer 与 return
在有命名返回值的函数中, 执行 return "风清扬"的时候实际上已经将 s 的值重新赋值为 风清扬
func Users2() (s string) {s = "乔峰"defer func() {fmt.Println("延迟执行后:" + s)}()return "清风扬"
}func TestDefer7(t *testing.T) {Users2() // 输出:延迟执行后:清风扬
}
输出结果:
延迟执行后:清风扬
--- PASS: TestDefer7 (0.00s)
PASS
欢迎关注公众号:程序员开发者社区
参考资料
- https://www.cnblogs.com/phpper/p/11984161.html
- https://draveness.me/golang/docs/part2-foundation/ch05-keyword/golang-defer/
Go defer 使用相关推荐
- Go 学习笔记(17)— 函数(03)[defer 定义、defer 特点、defer 释放资源]
1. defer 定义 Go 函数的关键字 defer 可以提供注册多个延迟调用,只能出现在函数内部,在 defer 归属的函数即将返回时,将延迟处理的语句按 defer 的逆序进行执行,这些调用遵循 ...
- Go基础编程:延迟调用defer
链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载. 本篇文章所讲的就是go编程中的延迟调用defer,希望对社区的成员有较多的帮助. 1 defer作用 关键字defer ...
- js的defer属性
js的defer属性说明:<script src="js.js" type="text/javascript defer="defer"/> ...
- golang源码分析:defer流程分析
defer defer是golang中使用的延迟调用的函数,该函数的使用场景就是如果函数执行出错(panic),也能够通过recover方式进行捕捉错误并将出错时的一些资源进行回收,如果在性能有要求的 ...
- Script标签的async和defer
之前有写过HTML页面渲染过程,知道了JavaScript是会阻塞DOM解析的,所以我们会把script标签放到底部防止阻塞HTML解析.其实script还有两个属性,async和defer,也是可以 ...
- prefetch 和preload_前端preload, prefetch,dns-prefetch,defer,async了解一下
preload 通过rel="preload"进行内容预加载 元素的 rel 属性的属性值preload能够让你在你的HTML页面中 元素内部书写一些声明式的资源获取请求,可以指明 ...
- GO语言教程4:defer(延迟语句)详解
文章目录 1.defer语句格式 2.defer执行的时间 3.defer语句的作用 4.defer语句执行的顺序 5.defer与return的value之间的关系 6.用defer进行代码跟踪 7 ...
- script标签的defer属性
defer 属性规定是否对脚本执行进行延迟,直到页面加载为止. 有的 javascript 脚本 document.write 方法来创建当前的文档内容,其他脚本就不一定是了. 如果您的脚本不会改变文 ...
- Go笔记-错误处理和defer
为什么80%的码农都做不了架构师?>>> error error类型的声明可在builtin包中查看: type error interface {Error() string } ...
- Js高设笔记1-2章 defer and async
1,js是由ECMAscript ,dom ,bom组成的专为网页交互而设计的脚本语言.js是脚本语言之一. 2,MIME,是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的 ...
最新文章
- Postman批量跑接口
- VTK:PolyData之PolyDataToUnstructuredGrid
- label 标签里面元素点击事件
- Qt学习笔记-编写简易的音乐播放器
- vSphere 7 With K8s系列07:客户端工具使用
- 毕设周记——确定选题
- win10安装nessus8.10
- node 简繁体转换_简体繁体转换
- IB选课指南及热门专业选课建议
- android 点击提示音,Android 下实现------蜂鸣提示音和震动
- 共阳极管的代码_共阳极数码管显示数字程序的进化
- ps有一款比较好用的插件也就是调色插件用过吗
- R 语言中添加辅助线(ggplot2)
- Paxos太难懂?五张图读懂Paxos协议
- 第十三届蓝桥杯国赛真题 PythonB组 复盘以及获奖感言(国一!!!)
- c语言中输入scanf与getchar的啃爹之处
- 第一次参加区赛的收获——By Yvonne
- 判断OOBE 完成状态
- delphi function 与 procedure
- 每天学一点Scala之implict 隐式参数