go defer
//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()捕获住
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!