Go 中 defer 的机制

news/2025/2/3 9:06:28 标签: golang, 开发语言, 后端

文章目录

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

输出:

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

结论

  • 若参数是值类型(如 intstring),defer 会拷贝当前值,后续修改不影响已注册的 defer
  • 若参数是指针或引用类型(如 *intslice),拷贝的是地址,后续修改会影响 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 通过地址修改原变量,影响最终结果。

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


http://www.niftyadmin.cn/n/5840660.html

相关文章

【深度学习】softmax回归的简洁实现

softmax回归的简洁实现 我们发现(通过深度学习框架的高级API能够使实现)(softmax)线性(回归变得更加容易)。 同样,通过深度学习框架的高级API也能更方便地实现softmax回归模型。 本节继续使用Fashion-MNIST数据集,并保持批量大小为256。 import torch …

SuccessFactors OData OAuth with SAP IAS-generated SAML assertion

导读 IAS:一句话说明白。SAP相关的系统可以通过IAS登录,只要IAS登录,其他系统免密登录。 作者:vivi,来源:osinnovation 上图有三个角色:brower,就是自己的浏览器,sp就是我们的目标…

Verilog语言学习总结

Verilog语言学习! 目录 文章目录 前言 一、Verilog语言是什么? 1.1 Verilog简介 1.2 Verilog 和 C 的区别 1.3 Verilog 学习 二、Verilog基础知识 2.1 Verilog 的逻辑值 2.2 数字进制 2.3 Verilog标识符 2.4 Verilog 的数据类型 2.4.1 寄存器类型 2.4.2 …

【前端知识】常用CSS样式举例

文章目录 一、Flex盒子布局1. Flexbox 的基本概念2. Flex 容器的属性2.1 display2.2 flex-direction2.3 flex-wrap2.4 justify-content2.5 align-items2.6 align-content 3. Flex 项目的属性3.1 order3.2 flex-grow3.3 flex-shrink3.4 flex-basis3.5 flex3.6 align-self 4. 示例…

流媒体娱乐服务平台在AWS上使用Presto作为大数据的交互式查询引擎的具体流程和代码

一家流媒体娱乐服务平台拥有庞大的用户群体和海量的数据。为了高效处理和分析这些数据,它选择了Presto作为其在AWS EMR上的大数据查询引擎。在AWS EMR上使用Presto取得了显著的成果和收获。这些成果不仅提升了数据查询效率,降低了运维成本,还…

指导初学者使用Anaconda运行GitHub上One - DM项目的步骤

以下是指导初学者使用Anaconda运行GitHub上One - DM项目的步骤: 1. 安装Anaconda 下载Anaconda: 让初学者访问Anaconda官网(https://www.anaconda.com/products/distribution),根据其操作系统(Windows、M…

【大数据技术】教程02:搭建完全分布式高可用大数据集群(Hadoop+MapReduce+Yarn)

搭建完全分布式高可用大数据集群(Hadoop+MapReduce+Yarn) jdk-8u361-linux-x64.tarhadoop-3.3.6.tar.gz注:请在阅读本篇文章前,将以上资源下载下来。 写在前面 本文主要介绍搭建完全分布式高可用集群Hadoop+MapReduce+Yarn的详细步骤。 注意: 统一约定将软件安装包存放…

深度解析:网站快速收录与网站安全性的关系

本文转自:百万收录网 原文链接:https://www.baiwanshoulu.com/58.html 网站快速收录与网站安全性之间存在着密切的关系。以下是对这一关系的深度解析: 一、网站安全性对收录的影响 搜索引擎惩罚: 如果一个网站存在安全隐患&am…