news 2026/6/25 16:48:34

Go Defer语句详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Go Defer语句详解

在实际编程中,我们经常需要清理一些资源,比如打开的文件数据库连接等。当程序不再使用这些资源时,及时关闭它们非常重要,否则可能会造成:

  • 内存泄漏

  • 文件或连接被长期占用

  • 其他程序无法访问这些资源

在本节中,我们将学习 Go 语言中的一个特殊语句,它可以帮助我们在程序执行过程中自动清理资源,让代码更加简洁、安全、不易出错,并且让“关闭资源”的代码紧挨着“打开资源”的代码,提高可读性。


defer语句

在 Go 中,我们使用defer语句延迟执行一个函数,直到包含它的函数即将返回时才执行。


defer的基本用法

下面是一个最基础的例子:

packagemainimport"fmt"funcmain(){deferfmt.Println("Printed second! 2")fmt.Println("Printed first! 1")}

输出结果:

Printed first!1Printed second!2

代码解释

虽然"Printed second! 2"在代码中先出现,但它并没有先输出。

这是因为:

任何使用defer修饰的语句,都会等到当前函数执行结束时才被调用。


多个defer语句

在 Go 程序中,可以有多个defer语句。
当存在多个defer时,它们会被当作一个栈来管理

来看下面的例子:

packagemainimport"fmt"funcmain(){deferfmt.Println("🐥")// 第 1 个 deferdeferfmt.Println("🐣")// 第 2 个 deferdeferfmt.Println("🥚")// 第 3 个 defer}

输出结果:

🥚 🐣 🐥

代码解释

  • 🐥最先被 defer 的,但最后执行

  • 🥚最后被 defer 的,却最先执行

这说明:

defer的执行顺序是后进先出(LIFO,Last In First Out)

可以把它理解为一个栈结构

defer🐥defer🐣defer🥚 ← 先执行

多个函数中的defer

当多个函数中都包含defer时,需要注意:

defer只在它所在的函数结束时才会执行

来看下面的例子:

packagemainimport"fmt"funcgreeting(){deferfmt.Println("Printed after Hello, JB Academy!")// 2fmt.Println("Hello, JB Academy!")// 1}funcmain(){deferfmt.Println("Printed after the main() function is completed.")// 4greeting()fmt.Println("Printed after calling the greeting() function.")// 3}

输出结果:

Hello,JB Academy!Printed after Hello,JB Academy!Printed after calling thegreeting()function.Printed after themain()function is completed.

代码解释

执行顺序如下:

  1. greeting()内部先打印
    Hello, JB Academy!

  2. greeting()结束
    → 执行其defer

  3. 回到main()
    → 打印普通语句

  4. main()结束
    → 执行main()中的defer

结论:

每个函数中的defer,都会在该函数结束时立即执行,与其他函数互不影响。


作用域中的defer

再看一个关于作用域的例子:

funcscopedDefer(){n:=0deferfunc(){fmt.Println("n =",n,"- first deferred print")}(){deferfunc(){fmt.Println("n =",n,"- second deferred print")}()n++// n = 1}n++// n = 2}

输出结果:

n=2-second deferredprintn=2-first deferredprint

代码解释

  • 两个defer都在scopedDefer()函数中

  • 即使其中一个写在代码块{}内,它们也不会提前执行

  • 都要等到scopedDefer()函数结束

  • 执行时,变量n的值已经变成2

说明:

defer的执行时间与函数结束有关,而不是代码块结束。


使用defer关闭文件(最常见用法)

defer最常见、最重要的用途之一,就是释放资源,例如关闭文件。

packagemainimport("fmt""log""os")funcmain(){file,err:=os.Create("test.txt")iferr!=nil{log.Fatal(err)}deferfile.Close()// 程序结束前自动关闭文件if_,err:=fmt.Fprintln(file,"Hello World!");err!=nil{log.Fatal(err)}}

代码解释

  • os.Create()创建并打开文件

  • defer file.Close()保证函数结束前文件一定会被关闭

  • 即使中途return或发生错误,也不会忘记关闭文件


为什么要用defer关闭资源?

使用defer有两个明显优点:

1. 防止忘记关闭资源

如果以后给函数增加新的return路径,也不用担心遗漏Close()

2. 代码更清晰

“打开资源”和“关闭资源”写在一起,可读性更好,而不是把Close()放在函数结尾。


总结

在本节中,主要内容包括:

  • defer会在当前函数返回前执行

  • 多个defer后进先出(LIFO)顺序执行

  • defer的作用域是函数级别

  • defer最常见的用途是关闭文件、释放资源

掌握defer是写出安全、优雅 Go 代码的重要一步。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/24 19:39:13

SQL Server重复记录查询、删除处理

1、查找表中多余的重复记录,重复记录是根据单个字段(aID)来判断 select * from A where aID in (select aID from A group by aID having count(aID) > 1) 例二: select * from testB where numeber in (select number from A group by number having count(…

作者头像 李华
网站建设 2026/6/24 22:17:01

复制字符串而不是直接赋值指针

复制字符串而不是直接赋值指针 (LeetCode:2418.按身高排序) 1.why?数据独立性: 复制字符串使返回结果与输入数据完全独立 修改返回数组中的字符串不会意外影响原始数据(可移植性) 原始数据被释放…

作者头像 李华
网站建设 2026/6/24 12:32:25

Kotaemon:基于Gradio的RAG文档对话工具安装与配置

Kotaemon:基于Gradio的RAG文档对话工具安装与配置 在企业知识管理日益复杂的今天,如何让AI真正“读懂”内部文档,并以自然语言准确作答,成为智能客服、知识助手等场景的核心挑战。传统的问答系统常因信息孤岛或上下文缺失而表现不…

作者头像 李华
网站建设 2026/6/24 18:19:27

基于Android的大学生校园互帮APP的设计与实现(源码+lw+部署文档+讲解等)

课题介绍本课题聚焦大学生校园内需求匹配低效、互助渠道单一的痛点,设计实现基于 Android 的大学生校园互帮 APP。系统以 Java 为核心开发语言,基于 Android 原生框架搭建移动端应用,搭配轻量后端服务架构,处理需求发布、技能匹配…

作者头像 李华
网站建设 2026/6/22 1:37:47

LobeChat:全栈开发现代化AI聊天应用

LobeChat:构建现代 AI 聊天应用的全栈实践 在生成式 AI 浪潮席卷各行各业的今天,一个直观、灵活且可定制的对话界面,已成为连接用户与大模型能力的关键入口。然而,从零开发一套稳定、美观、功能完整的 AI 聊天系统——支持多模型切…

作者头像 李华
网站建设 2026/6/25 12:54:27

LobeChat能否取代官方ChatGPT客户端?对比评测来了

LobeChat能否取代官方ChatGPT客户端?对比评测来了 在企业越来越依赖大模型构建智能系统、开发者渴望更自由AI交互入口的今天,一个开源项目正悄然改变游戏规则——LobeChat。它不再只是“另一个聊天界面”,而是试图成为连接人与多模态AI能力的…

作者头像 李华