什么是defer
在Go语言中,defer 是一种用于延迟执行函数调用的关键字。通过使用 defer,我们可以将函数调用推迟到包含 defer 语句的函数即将返回之前执行。无论函数是通过正常返回还是通过发生错误而返回,defer 语句都会被执行。
func count(x int) {
fmt.Printf("倒计时: %d\n", x)
}
func TestDefer(T *testing.T) {
defer count(1)
defer count(2)
defer count(3)
fmt.Println("开始倒计时")
}
如上述代码最终会输出:
开始倒计时
倒计时: 3
倒计时: 2
倒计时: 1
在 Go 语言中,如果有一个 defer 语句定义在 return 语句之前,那么在执行 return 到函数最终返回之前,defer 语句中的代码会按照后进先出(LIFO,Last In, First Out)的顺序执行。即先定义后执行,这意味着最后一个进入的 defer 语句会最先执行,然后是倒数第二个,以此类推,直到最先进入的 defer 语句执行。
defer与函数return
当一个函数中既包含了 defer 语句又有 return 语句时,它们的执行顺序如下:
- 当函数执行到
defer语句时,会将defer后面的表达式或函数调用压入一个栈中,但不会立即执行。这样做的目的是为了延迟函数的执行,将其放在函数返回之后执行。 - 接着,函数会执行
return语句,并将返回结果保存下来。请注意,这里的返回结果并不是最终的函数返回结果,而是在return语句中指定的结果。 - 最后,函数会从栈中按照后进先出(LIFO)的顺序取出被推迟的函数调用,并执行它们。这意味着
defer语句中的函数调用会在函数返回之后执行。
通过defer修改返回值
函数执行return时,返回结果不一定是最终的结果,他有可能被return之前的defer修改
- 示例1
func demo1() *int {
a := 7
defer func() {
a++
}()
return &a
}
func demo2() *int {
var a *int = new(int)
defer func() {
*a++
}()
return a
}
在demo1中函数返回了变量a的地址,defer中对a的值+1,最终返回值变量地址的引用,所以最终结果取值会是8;demo2也是同理,最终返回取值会是1
- 示例2
func demo3() int {
a := 7
defer func() {
a++
}()
return a
}
func demo4() int {
var a *int = new(int)
defer func() {
*a++
}()
return *a
}
这里demo3和demo4会返回7和0,这是因为在defer执行前,返回值已经分别被赋为7和0,在defer中再去对函数内局部变量做修改,并不会改变return的值
- 示例3
func demo5() (x int) {
defer func() {
x++
}()
return 7
}
这里demo5会返回8,它和demo3的区别在于,demo5的返回值在函数定义是声明了变量名,defer对返回值进行自增,最后返回的为自增后的值
总结
- 如果函数返回的是变量的指针,在
return之前的defer对变量值进行了修改,最终返回的是指向修改后变量的指针 - 如果函数返回的是未命名的变量值,在
return之前的defer对变量值进行修改,最终返回的还会是修改前的值 - 如果函数返回的是已命名的变量值,在
return之前的defer对变量值进行修改,最终返回的是修改后的值