深入理解Go中defer的机制
defer 是 Go 语言中用于延迟执行函数调用的关键字,常用于资源清理(如关闭文件、释放锁)和异常处理。但其行为机制存在一些隐蔽的细节,稍有不慎可能导致难以察觉的 Bug。本文通过多个直观示例,深入剖析 defer 的核心机制。
一、defer 的执行顺序:后进先出(LIFO)
多个 defer 语句按逆序执行,类似于栈的“后进先出”原则。
示例 :多个 defer 的执行顺序
func main() {
defer fmt.Println("defer 1")
defer fmt.Println("defer 2")
fmt.Println("main 逻辑")
}
输出:
main 逻辑
defer 2
defer 1
结论:
defer语句按注册顺序的逆序执行,确保依赖资源按正确顺序释放(如先打开的文件后关闭)。
二、defer 的参数预计算:值拷贝的陷阱
defer 的参数在注册时即被预计算并拷贝,而非执行时动态获取。
示例 :参数预计算的影响
func main() {
x := 10
defer fmt.Println("defer 中的 x:", x) // x 的值在注册时被拷贝
x = 20
fmt.Println("main 中的 x:", x)
}
输出:
main 中的 x: 20
defer 中的 x: 10
结论:
- 若参数是值类型(如
int、string),defer会拷贝当前值,后续修改不影响已注册的defer。 - 若参数是指针或引用类型(如
*int、slice),拷贝的是地址,后续修改会影响defer的执行结果。
三、defer 与闭包:动态绑定的变量
defer 函数若使用外部变量(闭包),会引用变量的最新值,而非注册时的值。
示例 :闭包中的变量绑定
func main() {
x := 10
defer func() {
fmt.Println("defer 中的 x:", x) // 闭包引用最新值
}()
x = 20
fmt.Println("main 中的 x:", x)
}
输出:
main 中的 x: 20
defer 中的 x: 20
结论:
- 闭包中的变量在
defer执行时才求值,因此会反映变量的最终状态。 - 若需固定闭包中的值,需在注册时通过参数传递(如
defer func(a int) { ... }(x))。
四、defer 与返回值:隐式的赋值逻辑
defer 中修改返回值的行为取决于返回值的定义方式(值返回 vs 指针返回)。
示例 4:值返回与指针返回的差异
// 值返回:defer 修改不影响返回值
func f1() int {
x := 10
defer func() { x++ }()
return x // 实际返回的是 x 的拷贝
}
// 指针返回:defer 修改影响返回值
func f2() *int {
x := 10
defer func() { x++ }()
return &x // 返回 x 的地址
}
func main() {
fmt.Println(f1()) // 输出 10
fmt.Println(*f2()) // 输出 11
}
结论:
- 值返回:返回值在
return时被拷贝,defer修改原变量不影响已拷贝的值。 - 指针返回:返回的是变量地址,
defer通过地址修改原变量,影响最终结果。
到此这篇关于Go中defer的机制的文章就介绍到这了,更多相关Go defer机制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
小学生也能看懂的Golang异常处理recover panic
在其他语言里,宕机往往以异常的形式存在,底层抛出异常,上层逻辑通过 try/catch 机制捕获异常,没有被捕获的严重异常会导致宕机,go语言追求简洁,优雅,Go语言不支持传统的 try…catch…finally 这种异常2021-09-09
Golang标准库os/exec执行外部命令并获取其输出包代码示例
这篇文章主要为大家介绍了Golang标准库os/exec执行外部命令并获取其输出包代码示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪2023-12-12
golang 日志库ZAP[uber-go zap]示例详解
ZAP是由Uber开源的高性能Go语言日志库,支持多种日志级别及基本信息打印,虽然ZAP本身不支持日志分割,但可以结合lumberjack进行日志切割,实现日志按文件大小、时间或间隔切割等功能,ZAP提供Logger和SugaredLogger两种日志记录器2024-10-10
浅析Go中fasthttp与net/http的性能对比及应用
这篇文章主要为大家详细介绍了Golang中fasthttp的底层实现以及与net/http的区别,下面就跟随小编一起来看看fasthttp到底是如何做到性能如此之快的吧2024-03-03


最新评论