go语言中的一个关键字、作用在函数作用域中、用于在函数结束之前的代码逻辑执行。
1. 多个defer之间是栈的关系、先进后出。
2. defer与return
已知return是作为当前函数的最后一条执行语句、也就是函数作用域还没有结束,defer触发时机是当前函数作用域结束、所以先执行return在执行defer。
3. 函数返回值的初始化
func DeferFunc1(i int) (t int) { // 初始化i = 10 t = 0
fmt.Println("t = ",t) //打印t = 0
return 2 // 返回t = 2
}
func main(){
DeferFunc1(10)
}
// 该函数输出结果为04. 有名函数返回值与defer
func DeferFunc2() (t int) {
defer func(){
t = t * 10
}()
return 1
}
func main(){
fmt.Println(DeferFunc2())
}
// 该函数输出结果为10 先初始化t = 0 然后return t = 1 最后执行defer t = t*10=10
//需要注意的是执行return之后并不代表返回值已经确定了5. defer与panic
5.1panic之后强制defer出栈,panic之后的defer不再执行
5.2即使触发了panic,panic之前的defer也会被执行
6. defer包含panic
func main(){
defer func(){
if err := recover(); err != nil {
fmt.Println(err)
}else{
fmt.Print("fatal")
}
}()
defer func() {
panic("defer panic")
}()
panic("panic")
}
// 输出结果defer panic
// panic只有最后一个才可以被recover捕获
//先执行panic、然后触发defer、先触发第二个defer、第二个defer再次触发panic,覆盖掉第一个panic、
//然后执行第一个defer,触发recover捕获panic(由于第一个已经被覆盖掉了,所以这里捕获的是defer里面的panic)
//打印出defer panic7. defer下的函数参数包含子函数
func DeferFunc7(index int,value int) int {
fmt.Print(index)
return index
}
func main() {
defer DeferFunc7(1, DeferFunc7(3,0))
defer DeferFunc7(2, DeferFunc7(4,0))
}
//打印顺序3、4、2、1
//多个defer是按照栈的形式先进后出,但是在压栈的时候需要将函数地址,函数参数一同进栈,所以为了先算出
//外层defer函数的参数、需要先执行defer里面的函数
//压栈1函数地址、形参1、行参2(调用3)、打印3
//压栈2函数地址、形参1、行参2(调用4)、打印4
//出栈2,打印2
//出栈1,打印18. 案列
func DeferFunc() (t int) {
defer func(i int) {
fmt.Print(i)
fmt.Print(t)
}(t)
t = 1
return 2
}这个案列可以先试着解一下输出内容、然后再看后面的
先初始化 t = 0、然后执行defer中t入参为0、接着t = 1 t = 2
由于t被赋值之前已经传给了defer,所以i = 0、t = 2
输出 0、2(这里由于压栈的时候要把参数传进去,所以先把t = 0给传进去了,可以看7)