go defer

发布时间 2023-12-19 11:29:09作者: HHMLXL
//defer 作用域在当前函数和方法返回之前被调用
// return 比 defer  更先执行

package main

import "fmt"

func deferFunc() int {
    fmt.Println("defer func done")
    return 0
}

func returnFunc() int {
    fmt.Println("return func done")
    return 0
}

func returnAndDefer() int {
    defer deferFunc()
    return returnFunc()
}

func main() {
    returnAndDefer()
}

$ go run main.go
return func done
defer func done

 


package
main import "fmt" func main() { { defer fmt.Println("defer done") fmt.Println("code block done") } fmt.Println("main done") } // go run main.go // code block done // main done // defer done

 

// defer 执行顺序,先进后出

package main

import "fmt"

func main() {
    defer funcA()
    defer funcB()
    defer funcC()
}

func funcA() {
    fmt.Println("A")
}

func funcB() {
    fmt.Println("B")
}

func funcC() {
    fmt.Println("C")
}

$ go run main.go
C
B
A
// defer 影响主函数的具名返回值
// 当主函数有返回值,且返回值有没有名字没有关系,defer所作用的函数,即defer可能会影响主函数的返回值

package main

import "fmt"

func main() {
    fmt.Println(deferFunc())

    fmt.Println("main done")
}

func deferFunc() (j int) {
    i := 1
    defer func() {
        j++
    }()

    return i

}

// go run main.go

// 2

func main() {
    fmt.Println(deferFuncReturn())
}
func deferFuncReturn() int {
    i := 1
    defer func() {
        i++
    }()
    return i
}

$ go run main.go
1

结论:当主函数有返回值 ,会在函数初始化时赋值为0,且其作用域为该函数全域,defer 会影响到该返回值。
 

 

 

defer 偶遇 panic

在 Golang 中,执行过程中遇到 panic 错误时,遍历所有defer,强行 defer 出栈,并执行 defer。在执行过程中,

遇到 recover 捕获异常停止 panic,返回 recover 继续执行
未设置 recover 捕获异常,遍历完 defer 抛出 panic 信息


1.defer 未捕获 panic

package main

import (
    "fmt"
)

func main() {
    defer_call()

    fmt.Println("main done...")
}

func defer_call() {
    defer func() { 
        fmt.Println("defer func 1") 
    }()
    defer func() { 
        fmt.Println("defer func 2") 
    }()

    // 触发defer出
    panic("error1") 

    defer func() {
        fmt.Println("defer func 3: no exec")
    }()
}
$ go run main.go
defer func 2
defer func 1
panic:error1
... 堆栈error...
main.defer_call()
        /Users/dip/go/src/prc-gorm/main.go:22 +0x4e
main.main()
        /Users/dip/go/src/prc-gorm/main.go:8 +0x13
exit status 2




2.defer 捕获 panic

package main

import (
    "fmt"
)

func main() {
    defer_call()

    fmt.Println("main done...")
}

func defer_call() {

    defer func() {
        fmt.Println("defer func 1, 捕获异常")
        if err := recover(); err != nil {
            fmt.Println(err, "333")
        }

    }()
    defer func() {
        fmt.Println("defer func 2, 没有捕获异常")
    }()

    // 触发defer出
    panic("error11111")

    defer func() {
        fmt.Println("defer func 3: no exec")
    }()

}


(base) dip@DipdeMacBook-Pro prc-gorm % go run main.go
defer func 2, 没有捕获异常
defer func 1, 捕获异常
error11111 333
main done...



3 defer 中含有 panic
Golang 中,panic 仅会被最后一个 revover 捕获。
package main

import (
    "fmt"
)


func main()  {
    defer func() {
       if err := recover(); err != nil{
           fmt.Println("err:", err)
       }else {
           fmt.Println("fatal")
       }
    }()

    defer func() {
        panic("defer panic2")
    }()

    panic("panic1")
}
$ go run main.go
err: defer panic2

在上面例子中,panic("panic1")先 触发 defer 强制出栈,第一个执行触发 panic("defer panic2)"异常,此时会覆盖前一个异常 panic,最后继续执行 defer, 最终被 recover()捕获住