Go 中 defer 的机制

ops/2025/2/4 23:58:27/

文章目录

    • Go 语言中 `defer` 的底层机制与实战解析
      • 一、`defer` 的执行顺序:后进先出(LIFO)
        • 示例 :多个 `defer` 的执行顺序
      • 二、`defer` 的参数预计算:值拷贝的陷阱
        • 示例 :参数预计算的影响
      • 三、`defer` 与闭包:动态绑定的变量
        • 示例 :闭包中的变量绑定
      • 四、`defer` 与返回值:隐式的赋值逻辑
        • 示例 4:值返回与指针返回的差异

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 := 10defer fmt.Println("defer 中的 x:", x) // x 的值在注册时被拷贝x = 20fmt.Println("main 中的 x:", x)
}

输出:

main 中的 x: 20
defer 中的 x: 10

结论

  • 若参数是值类型(如 intstring),defer 会拷贝当前值,后续修改不影响已注册的 defer
  • 若参数是指针或引用类型(如 *intslice),拷贝的是地址,后续修改会影响 defer 的执行结果。

三、defer 与闭包:动态绑定的变量

defer 函数若使用外部变量(闭包),会引用变量的最新值,而非注册时的值。

示例 :闭包中的变量绑定
func main() {x := 10defer func() {fmt.Println("defer 中的 x:", x) // 闭包引用最新值}()x = 20fmt.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 := 10defer func() { x++ }()return x // 实际返回的是 x 的拷贝
}// 指针返回:defer 修改影响返回值
func f2() *int {x := 10defer func() { x++ }()return &x // 返回 x 的地址
}func main() {fmt.Println(f1()) // 输出 10fmt.Println(*f2()) // 输出 11
}

结论

  • 值返回:返回值在 return 时被拷贝,defer 修改原变量不影响已拷贝的值。
  • 指针返回:返回的是变量地址,defer 通过地址修改原变量,影响最终结果。

若有错误与不足请指出,关注DPT一起进步吧!!!


http://www.ppmy.cn/ops/155711.html

相关文章

JavaScript反爬技术解析与应对

JavaScript 反爬技术解析与应对 前言 在当今 Web 爬虫与数据抓取的生态环境中,网站运营方日益关注数据安全与隐私保护,因此逐步采用多种反爬技术来限制非授权访问。本文从 JavaScript 角度出发,深入剖析主流反爬策略的技术原理,…

深度学习之“向量范数和距离度量”

在深度学习中,范数和向量距离是两个不同的概念。向量范数是一种函数,用于将一个实数或复数向量映射为一个值。虽然范数通常用于度量向量之间的距离,但是同样也有其它的一些表示距离的方式。 范数距离 范数是具有“长度”概念的函数。在向量…

k8s二进制集群之ETCD集群证书生成

安装cfssl工具配置CA证书请求文件创建CA证书创建CA证书策略配置etcd证书请求文件生成etcd证书 继续上一篇文章《负载均衡器高可用部署》下面介绍一下etcd证书生成配置。其中涉及到的ip地址和证书基本信息请替换成你自己的信息。 安装cfssl工具 下载cfssl安装包 https://github…

Python中的函数(下)

函数返回值 返回单个值 函数可以通过 return 语句返回一个值。一旦执行到 return 语句,函数就会停止执行,并将指定的值返回给调用者。例如: 返回多个值 实际上,Python函数只能返回一个值,但可以通过返回一个元组来模…

系统思考—结构影响行为

“系统的行为是它结构的产物。要改变系统的行为,必须改变它的结构。”——德内拉梅多斯 很多企业在遇到问题时,习惯性的做法是换管理层、加大考核、调整激励机制,甚至开更多的会,但问题真的能解决吗?如果系统的底层逻…

AMD模块

AMD 与 CommonJS 在介绍 AMD 之前,我们需要了解 CommonJS 规范。CommonJS 是服务器端 JavaScript(如Node.js)的模块化标准,它使用同步方式加载模块。然而,这种方式并不适用于浏览器环境,因为 JavaScript 文…

解锁豆瓣高清海报(一) 深度爬虫与requests进阶之路

前瞻 PosterBandit 这个脚本能够根据用户指定的日期,爬取你看过的影视最高清的海报,然后使用 PixelWeaver.py 自动拼接成指定大小的长图。 你是否发现直接从豆瓣爬取下来的海报清晰度很低? 使用 .pic .nbg img CSS 选择器,在 我…

国产之DeepSeek认识、使用及影响

一、前言 2025年乙巳蛇年,DeekSeek彻底网络爆火,为更多国人熟知,在国外更是早先几月就引起Ai界轩然大波,对Ai界硬件显卡厂商英伟达和一众外国Ai资本和科技公司造成很大冲击。Deepseek公司同产品名,早在2023年7月已成立,由知名私募巨头幻方量化孕育而生 ,专注于开发先进的…