Go 中 defer 的机制

server/2025/2/5 1:39:15/

文章目录

    • 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/server/165035.html

相关文章

SAP HCM 回溯分析

最近总有人问回溯问题,今天把12年总结的笔记在这共享下: 12年开这个图的时候总是不明白是什么原理,教程看N次,网上资料找一大堆,就是不明白原理,后来为搞明白逻辑,按照教材的数据一样做&#xf…

基于单片机的车载传感器数据处理系统

1总体方案设计 本次新能源汽车车载传感器数据处理系统,其系统总体架构如图2.1所示,采用STM32f103单片机作为控制器,通过DH11传感器实现温湿度检测;通过光敏电阻实现光照检测;同时其检测的信息通过ESP8266 WiFi模块传输…

基于 YOLOv8+PyQt5 界面自适应的无人机红外目标检测系统项目介绍框架

基于 YOLOv8PyQt5 界面自适应的无人机红外目标检测系统项目介绍框架 【毕业与课程大作业参考】基于yolov8pyqt5界面自适应的无人机红外目标检测系统demo.zip资源-CSDN文库 (毕业设计 / 课程大作业参考方案) 一、项目背景与意义 无人机在军事侦察、灾害…

【蓝桥杯】43697.机器人塔

题目描述 X 星球的机器人表演拉拉队有两种服装,A 和 B。 他们这次表演的是搭机器人塔。 类似: A B B A B A A A B B B B B A B A B A B B A 队内的组塔规则是: A 只能站在 AA 或 BB 的肩上。 B 只能站在 AB 或 BA 的肩上。 你的…

Docker之Dockerfile

Docker之Dockerfile 1 参考2 Dockerfile讲解2.1 多个FROM2.2 COPY --from2.3 ARG指令 3 Dockerfile示例 1 参考 dockerfile 多FROMdockerfile中多个FROM指令的意义(multistage) 2 Dockerfile讲解 2.1 多个FROM Docker 17.05版本以后,新增了Dockerfile多阶段构建…

基于STM32的智能安防监控系统

1. 引言 随着物联网技术的普及,智能安防系统在家庭与工业场景中的应用日益广泛。本文设计了一款基于STM32的智能安防监控系统,集成人体感应、环境异常检测、图像识别与云端联动功能,支持实时报警、远程监控与数据回溯。该系统采用边缘计算与…

使用 HTTP::Server::Simple 实现轻量级 HTTP 服务器

在Perl中,HTTP::Server::Simple 模块提供了一种轻量级的方式来实现HTTP服务器。该模块简单易用,适合快速开发和测试HTTP服务。本文将详细介绍如何使用 HTTP::Server::Simple 模块创建和配置一个轻量级HTTP服务器。 安装 HTTP::Server::Simple 首先&…

grpc 和 http 的区别---二进制vsJSON编码

gRPC 和 HTTP 是两种广泛使用的通信协议,各自适用于不同的场景。以下是它们的详细对比与优势分析: 一、核心特性对比 特性gRPCHTTP协议基础基于 HTTP/2基于 HTTP/1.1 或 HTTP/2数据格式默认使用 Protobuf(二进制)通常使用 JSON/…