news 2026/7/12 2:19:48

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/7/11 14:01:14

LobeChat能否生成KPI指标?绩效考核智能化

LobeChat能否生成KPI指标?绩效考核智能化 在企业日常管理中,设定合理的KPI(关键绩效指标)从来都不是一件简单的事。HR常常面临这样的困境:员工提交的总结泛泛而谈,“完成项目支持”“协助团队推进”这类表述…

作者头像 李华
网站建设 2026/7/11 21:34:33

深入Spring Boot源码(四):Starter机制与依赖管理深度解析

前言在前面的文章中,我们深入剖析了Spring Boot的自动配置机制。然而,自动配置的实现离不开另一个核心概念——Starter。Starter是Spring Boot生态系统的基石,它将相关的依赖聚合在一起,并与自动配置紧密结合,真正实现…

作者头像 李华
网站建设 2026/7/11 20:46:13

SAPUI5 1.71.78老版本的消费restful服务

为了兼容老浏览器,没用Javascript的现代fetch api,用的jquerycontroller.js代码如下sap.ui.define(["sap/ui/core/mvc/Controller","sap/ui/model/json/JSONModel","sap/m/MessageToast" ], function (Controller, JSONMo…

作者头像 李华
网站建设 2026/7/11 11:03:54

Qwen3-14B-MLX-4bit长文本处理与YaRN扩展

Qwen3-14B-MLX-4bit长文本处理与YaRN扩展 在当前AI模型“军备竞赛”愈演愈烈的背景下,一味追求参数规模已不再是唯一解。越来越多的企业开始意识到:一个能在本地稳定运行、支持复杂任务编排、同时具备超长上下文理解能力的中型模型,往往比“云…

作者头像 李华
网站建设 2026/7/9 14:14:42

php小程序红色文物活动文创产品商城系统APP_2fil7831

文章目录 具体实现截图主要技术与实现手段关于我本系统开发思路java类核心代码部分展示结论源码lw获取/同行可拿货,招校园代理 :文章底部获取博主联系方式! 具体实现截图 同行可拿货,招校园代理 php小程序红色文物活动文创产品商城系统APP_2fil7831 …

作者头像 李华
网站建设 2026/7/11 3:16:10

Excalidraw:手绘风格开源白板工具详解

Excalidraw:当手绘遇上数字白板 你有没有过这样的经历?开会时想快速画个架构图,却卡在工具复杂的菜单里;写技术文档时需要一张示意图,结果花两小时调线条对齐;团队头脑风暴,想法满天飞&#xf…

作者头像 李华