0

0

标题:Go语言中对同一变量多次调用defer时的行为解析

心靈之曲

心靈之曲

发布时间:2026-01-26 22:14:01

|

645人浏览过

|

来源于php中文网

原创

标题:Go语言中对同一变量多次调用defer时的行为解析

go中,对同一变量多次使用defer调用方法时,最终执行的是哪个实例,取决于该方法的接收者类型(值接收者 or 指针接收者)以及变量本身的类型(值 or 指针),而非“最后一次赋值”的直观印象。

当你在函数中对同一个变量多次调用 defer rows.Close()(例如两次查询后都 defer 同一变量的 Close 方法),实际被关闭的对象并非由“最后一行赋值决定”,而是由 defer 语句执行时该变量的当前状态(尤其是其内存地址或值拷贝)决定。关键在于 Go 的 defer 机制:函数值与参数(含方法接收者)在 defer 语句执行时即被求值并保存,而非等到函数返回时才取值

? 核心规则总结:

  • ✅ *指针变量 + 指针接收者方法(如 `sql.Rows.Close())**:安全可靠。每次defer rows.Close()保存的是rows当前指向的地址;即使后续rows被重新赋值为另一个*sql.Rows,两次 defer 仍分别绑定到两个不同的底层资源。这是database/sql` 包能正确工作的根本原因。
  • ⚠️ 指针变量 + 值接收者方法:虽不常见,但此时接收者是 *X 的副本(即指针值本身被拷贝),两次 defer 保存的是不同指针值(地址),行为符合预期。
  • 值变量 + 值接收者方法:每次 defer 会拷贝整个结构体(如 X{...})作为接收者。第二次 defer 保存的是新赋值后的结构体副本,第一次的副本已固化——因此两次 Close 操作作用于两个独立副本,原始资源可能未被释放
  • ⚠️ 值变量 + 指针接收者方法危险! 此时 defer 保存的是该局部变量的地址(如 &x)。若后续修改 x,两次 defer 实际共享同一内存地址,最终两次 Close 都操作最后赋值的那个值(见下文示例输出中的 Value-X2 Second 重复出现),导致逻辑错误或资源泄漏。

? 示例验证(精简关键部分)

type X struct { S string }
func (x X) Close()      { fmt.Println("Value-Closing", x.S) }
func (x *X) CloseP()     { fmt.Println("Pointer-Closing", x.S) }

func main() {
    // 场景1:值变量 + 值接收者 → 两次 defer 保存不同副本
    x := X{"First"}; defer x.Close() // 保存 "First"
    x = X{"Second"}; defer x.Close() // 保存 "Second"
    // 输出:Value-Closing Second \n Value-Closing First

    // 场景2:值变量 + 指针接收者 → 两次 defer 保存同一地址(&x)
    x2 := X{"First"}; defer x2.CloseP() // 保存 &x2(指向"First")
    x2 = X{"Second"}; defer x2.CloseP() // 仍保存 &x2(现指向"Second")
    // 输出:Pointer-Closing Second \n Pointer-Closing Second ← 问题所在!

    // 场景3:指针变量 + 指针接收者 → 安全(推荐模式)
    xp := &X{"First"}; defer xp.Close() // 保存地址 A
    xp = &X{"Second"}; defer xp.Close() // 保存地址 B
    // 输出:Pointer-Closing Second \n Pointer-Closing First ← 正确关闭两个实例
}

✅ 最佳实践建议

  1. 优先使用独立变量名:避免歧义,提升可读性与可维护性:

    rows1 := db.Query("SELECT ..."); defer rows1.Close()
    rows2 := db.Query("SELECT ..."); defer rows2.Close()
  2. 理解 database/sql 的设计保障:sql.Rows 是指针类型,Close() 是指针接收者方法,因此你的原始代码(两次 defer rows.Close())在技术上是安全的——它会正确关闭两个查询结果集。但强烈建议改用独立变量,因为:

    ImgGood
    ImgGood

    免费在线AI照片编辑器

    下载
    • 符合直觉,降低认知负担;
    • 避免未来重构时因变量复用引入隐患;
    • 静态分析工具(如 govet)可能对重复 defer 发出警告。
  3. 自定义类型设计原则:若实现资源管理方法(如 Close()),始终使用指针接收者,并确保调用方持有指针(如通过 NewX() 返回 *X),以保证 defer 行为可预测。

    立即学习go语言免费学习笔记(深入)”;

? 总结:Go 的 defer 不是“延迟读取变量”,而是“延迟执行已冻结的函数+参数”。牢记 “defer 时求值,return 时执行” 这一原则,结合接收者类型与变量类型,即可准确预判资源清理行为。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

706

2023.10.12

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

327

2023.10.27

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

348

2024.02.23

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

1180

2024.03.06

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

360

2024.03.06

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

778

2024.04.07

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

579

2024.04.29

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

420

2024.04.29

拼多多赚钱的5种方法 拼多多赚钱的5种方法
拼多多赚钱的5种方法 拼多多赚钱的5种方法

在拼多多上赚钱主要可以通过无货源模式一件代发、精细化运营特色店铺、参与官方高流量活动、利用拼团机制社交裂变,以及成为多多进宝推广员这5种方法实现。核心策略在于通过低成本、高效率的供应链管理与营销,利用平台社交电商红利实现盈利。

31

2026.01.26

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go 教程
Go 教程

共32课时 | 4.2万人学习

Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号