什么是 defer
defer 是 Go 语言提供的一种用于注册延迟调用的机制,每一次 defer 都会把函数压入栈中,当前函数返回前再把延迟函数取出并执行。
1.defer 和panic 一起使用时执行顺序?
package main
import (
"fmt"
)
func main() {
defer_call()
}
func defer_call() {
defer func() { fmt.Println("打印前") }()
defer func() { fmt.Println("打印中") }()
defer func() { fmt.Println("打印后") }()
panic("触发异常")
}
defer 的执行顺序是后进先出。当出现 panic 语句的时候,会先按照 defer 的后进先出的顺序执行,最后才会执行panic。
2.defer 和带命名返回参数的函数一起使用
func f1() (r int) {
defer func() {
r++
}()
return 0
}
该程序的执行步骤为 1:r = return xxx,2 调用defer,3 return
因此该程序执行的结果为1.
func f2() (r int) {
t := 5
defer func() {
t = t + 5
}()
return t
}
1: r=t=5,2 defer,3 return
因为 defer 是对t 的操作,和r没有关系,所以程序返回值为5、
func f3() (r int) {
defer func(r int) {
r = r + 5
}(r)
return 1
}
1:r =1,2.defer 3. return
因为defer 是对局部变量的修改,不影响实参,因此返回值为1.
3. defer 和匿名返回值一起使用
func increaseA() int {
var i int
defer func() {
i++
}()
return i
}
对于匿名返回值来说,可以假设有一个返回值。设为tmp。
因此1:tmp=i=0,2:defer 3:return
所以defer修改的是i的值,和tmp没有关系,因此返回值为0.
4.defer 遇见return
var a bool = true
func main() {
defer func(){
fmt.Println("1")
}()
if a == true {
fmt.Println("2")
return
}
defer func(){
fmt.Println("3")
}()
}
该程序输出 2 1,defer 遇见return 不会执行。
5.
对于一个延迟函数的调用,它的实参是在此调用被推入延迟调用栈的时候被估值的
对于一个协程调用,它的实参是在此协程被创建的时候估值的
一个匿名函数体内的表达式是在此函数被执行的时候才会被逐个估值的。不管此函数是被普通函数还是延迟/协程调用
func F(n int) func() int {
return func() int {
n++
return n
}
}
func main() {
f := F(5)
defer func() {
fmt.Println(f())
}()//参见第三条,// 执行的时候才确定,因此为8
defer fmt.Println(f()) //参见第一条,因此入栈值确定为6.
i := f()
fmt.Println(i)//直接调用,因为值为7.
}