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