golang中的defer

golang中的defer

 次点击
9 分钟阅读

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)
}
// 该函数输出结果为0

4. 有名函数返回值与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 panic

7. 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,打印1

8. 案列

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)

© 本文著作权归作者所有,未经许可不得转载使用。