defer的使用
1、defer事什么?
defer是Go语言中代码延迟执行的语句,go语言代码段中的的defer
语句会将其后面跟随的语句进行延迟处理。在defer
归属的函数即将返回时,将延迟处理的语句按defer
定义的逆序进行执行,也就是说,先被defer
的语句最后被执行,最后被defer
的语句,最先被执行。(该特性联想进栈出栈,先进后出)
eg:
func main() {
fmt.Println("start")
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
fmt.Println("end")
}
执行结果:
/*
start
end
3
2
1
*/
2、defer的执行机制
在Go语言的函数中return
语句在底层并不是原子操作,它分为给返回值赋值和RET指令两步。而defer
语句执行的时机就在返回值赋值操作后,RET指令执行前。具体如下图所示:
3、练习题
package main
/*
defer 延迟执行,时机在第一步和第二步之间
return 不是原子操作,
第一步:返回值赋值
// defer
第二步:真正的RET指令返回
*/
func f1() int {
x := 5
defer func() {
x++ //该步骤修改的是变量x,不是返回值,该函数的关键点在于,返回值<未被命名>,函数的runtime应该为:
// 1,变量x被赋值5,2、返回值被赋值5 3、defer延迟执行修改变量x为6,4、最后执行return命令,返回了被赋值5的返回值
//
}()
return x // 5
}
func f11() (x int) {
defer func() { x++ }() // runtime:1、函数的返回值命名为x,初始值为0 ,return的非原子操作导致return语句的第一步使返回值x被赋值为5;
//2、执行defer操作,使变量x(即在内存地址上跟返回值为同一个)经过++运算变为6;3、执行真正的return操作返回返回值x,即为6
return 5 //6
}
func f2() (x int) {
a := 1
defer func() { //函数的runtime为:函数的返回值命名为x,初始值为0;变量a被赋值1;
x++ // return语句的实际执行步骤:
// 1、命名为x的返回值重新被赋值 x=a=1,
}() // 2、执行defer语句,x++, x = 1+1 = 2
// 3、执行真正的return指令,返回x为2
return a // 2
}
func f3() (y int) {
x := 5
defer func() {
x++
}()
return x //5 函数的runtime:函数的返回值命名为y,初始值为0;函数体中变量x被赋值5;
// return语句的实际执行步骤:
// 1、y = x = 5
// 2、defer执行:x=5+1=6
// 3、return真正执行,返回值y=5
}
func f4() (x int) {
defer func(x int) {
x++
}(x)
return 5 //函数的runtime:函数的返回值命名为x,初始值为0;
// return语句的实际执行步骤:
// 1、返回值被赋值x = 5
// 2、defer执行:x作为函数参数传入匿名函数,执行 x=5+1=6,但是 "函数传参修改的是副本"
// 3、return真正执行,返回值x=5
}
func f5() int {
x := 0
defer func(x int) {
x++
}(x)
return 5 // 5
}
func f6() (x int) {
defer func(x *int) {
*x++
}(&x)
return 5 // 6//函数的runtime:函数的返回值命名为x,初始值为0;
// return语句的实际执行步骤:
// 1、返回值被赋值x = 5
// 2、defer执行:x的指针作为函数参数传入匿名函数,执行 x=5+1=6,
// 3、return真正执行,返回值x=6
}
//func calc(index string, a, b int) int {
// ret := a + b
// fmt.Println(index, a, b, ret)
// return ret
//}
func f7() (x int) {
defer func(x int) int {
x++ // 传递的是x的副本,不会对原值有影响
return x
}(x)
return 5
}
func f8(x int) int {
//var x int
return func(x int) int {
x++
return x // 1
}(x)
//return
}
参考:https://www.liwenzhou.com/posts/Go/09_function/