defer

用于延迟函数的调用,每次defer都会把一个函数压入栈中,函数返回前再把延迟的函数取出并执行

数据结构

type _defer struct {
sp uintptr //函数栈指针
pc uintptr //程序计数器
fn *funcval //函数地址
link *_defer //指向自身结构的指针,用于链接多个defer
}

规则一:延迟函数的参数在defer语句出现时就已经确定下来了

如:

func a() {
i := 0
defer fmt.Println(i)
i++
return
}

defer语句中的fmt.Println()参数i值在defer出现时就已经确定下来,实际上是拷贝了一份。后面对变量i的修改不会影响fmt.Println()函数的执行,仍然打印”0”。但是注意 这里对于指针类型参数,仍然适用,所以defer后面的语句对变量修改还是会影响延迟函数如:

func a() {
i := []int{1,2,3}
defer fmt.Println(i)
i[0]=10
return
}//会输出[10,2,3],因为这里i为指针,是数组的地址

规则二:先进后出

很好理解,延迟函数执行按先进后出顺序执行,即先进去的defer最后执行

规则三:延迟函数可能操作主函数的具名返回值

defer可能会改变返回值,因为return语句不是原子的,实际执行为设置返回值-->ret

defer语句实际执行在返回前,即拥有defer的函数返回过程是:设置返回值–>执行defer–>ret。

注意:这里返回值必须要有具体名字

如下:

func deferFuncReturn() (result int) {
i := 1 defer func() {
result++
}() return i
}

输出2,return语句先把result设置为i的值,即1,defer语句又把result递增1,所以最终返回2

如果返回的是匿名变量,则不改变,如:

func foo() int {
var i int i=1
defer func() {
i++
}() return i
}

这里还是返回1,上面的返回语句可以拆分成以下过程:

t=i	//t就是要返回的值
i++
return //返回t,这里t还是1

最新文章

  1. andriod fragment调用Activity函数方法
  2. GBK 编码时 url 中带中文参数的问题
  3. 学习笔记-[Maven实战]-第二章:Maven安装和配置
  4. android中LayoutInflater详解与使用
  5. Java-反射再学习
  6. 算法导论(第三版)Exercises2.1(插入排序、线性查找、N位大数相加)
  7. javascript模式——Prototype模式
  8. Java中读取Excel功能实现_POI
  9. 【TensorFlow篇】--DNN初始和应用
  10. Sequence II HDU - 5919(主席树)
  11. 机器学习 xgboost 笔记
  12. Python_动态参数、名称空间、作用域、作用域链、加载顺序、函数的嵌套、global、nonlocal
  13. 「CodeForces - 717E」Paint it really, really dark gray (dfs)
  14. Redis入门——Java接口
  15. ClassThird
  16. java-方法重写和方法重载的区别
  17. Hibernate 的Ehache学习
  18. 2018haoi总结
  19. BZOJ2140: 稳定婚姻(tarjan解决稳定婚姻问题)
  20. SQL面试题(网络收集)

热门文章

  1. 痞子衡嵌入式:嵌入式Cortex-M裸机环境下临界区保护的三种实现
  2. kafka可视化工具
  3. tomcat内置jdk(tomcat集成jdk)(windows环境)
  4. 《手把手教你》系列技巧篇(十一)-java+ selenium自动化测试-元素定位大法之By tag name(详细教程)
  5. C语言学习之基本数据类型【一】
  6. Input 只能输入正数以及2位小数点
  7. noi linux 2.0 体验
  8. C++ //构造函数的分类及调用 //分类 // 按照参数分类 无参构造函数(默认构造) 有参构造函数 //按照类型分类 普通构造 拷贝构造
  9. Typora加七牛云实现实时图片自动上传
  10. 树莓派应用Docker