什么是defer

defer是Go语言提供的一种用于注册延迟调用的机制:让函数或语句可以在当前函数执行完毕后(包括通过return正常结束或者panic导致的异常结束)执行。

defer的应用场景

defer语句通常用于一些成对操作的场景:打开连接/关闭连接;加锁/释放锁;打开文件/关闭文件等。

defer的原理

defer语句并不会马上执行,而是会进入一个栈,函数return前,会按先进后出(FILO)的顺序执行。也就是说最先被定义的defer语句最后执行。先进后出的原因是后面定义的函数可能会依赖前面的资源,自然要先执行;否则,如果前面先执行,那后面函数的依赖就没有了。

defer的引用方式

defer语句定义时,对外部变量的引用有如下两种方式:

1.作为函数参数和作为闭包引用。作为函数参数,则在defer定义时就把值传递给defer,并被缓存起来。

2.作为闭包引用的话,则会在defer函数真正调用时根据整个上下文确定当前的值。

defer的踩坑点

避免踩坑的关键是要理解这条语句:

return xxx

这条语句经过编译之后,会变成了三条指令:

1. 返回值 = xxx
2. 调用defer函数
3. 空的return

第1,3 步才是return 语句真正的命令,第2步是 defer的定义语句,这里就有可能会操作返回值。

代码示例

示例1:

func f() (r int) {
defer func() {
r++
}()
return 0
}

拆解过程:

func f() (r int) {

    // 1.赋值
r = 0 // 2.闭包引用,返回值被修改
defer func() {
r++
}() // 3.空的return
return
}

由于defer是闭包引用,返回值被修改,所以f()返回 1。

示例2:

func f() (r int) {
t := 5
defer func() {
t = t + 5
}()
return t
}

拆解过程:

func f() (r int) {
t := 5
// 1.赋值
r = t // 2.闭包引用,但是没有修改返回值r
defer func() {
t = t + 5
}() // 3.空的return
return
}

由于第2步未涉及返回值r的操作,所以返回5。

示例3:

func f() (r int) {
defer func(r int) {
r = r + 5
}(r)
return 1
}

拆解过程:

func f() (r int) {

    // 1.赋值
r = 1 // 2.r作为函数参数,不会修改要返回的那个r值
defer func(r int) {
r = r + 5
}(r) // 3.空的return
return
}

由于第2步中r是作为函数参数使用,只是一份拷贝,defer语句里面的r和外面的r其实是两个变量,里面变量r的改变不会影响外层变量r,所以不是返回6,而是返回1。


个人主页:

www.codeapes.cn

最新文章

  1. DELL灵越15R5521安装黑苹果
  2. JavaWeb学习总结-05 Servlet 与页面的交互(02)
  3. 一个基于ANTLR 4的布尔表达式语句解释器的实现
  4. struts2基本配置
  5. 支付宝也要上"服务号"?斗战微信继续升级
  6. 再论pyquery
  7. Node.js的简介和安装
  8. linux下DNS设置以及解析顺序
  9. 【转】使用 Auto Layout 的典型痛点和技巧
  10. LINUX Shell 下求两个文件交集和差集的办法
  11. myEclipse修改deploy location
  12. Android 源码编译环境搭建(64位Ubuntu)各种依赖包安装
  13. BZOJ3036绿豆蛙的归宿
  14. Jsoup(一)Jsoup详解(官方)
  15. VantPy自动化测试框架
  16. Snagit for mac(截图软件)中文版,截个图就是这么容易!
  17. 026 UI调试
  18. chromedriver和chrome匹配的版本
  19. MVC的项目部署成应用程序或虚拟目录路径的问题
  20. MTK 强制横屏

热门文章

  1. ROS自动切换策略
  2. Ubuntu安装并使用emacs
  3. noi.ac-CSP模拟Day5T1 组【二分图最大匹配】
  4. Hbase 0.92.1 Replication
  5. Linux上面执行 Windows 命令(比如 重启服务)的简单方法
  6. urllib库:分析Robots协议
  7. [转帖]56核Xeon Platinum 9200现身 - 英特尔有史以来最大的CPU封装
  8. React基础篇学习
  9. Java细节----method和function的区别
  10. CF 1136C Nastya Is Transposing Matrices