当前位置: 首页 > news >正文

Go的defer和recover

在 Go 语言中,deferrecover 是两个紧密相关的关键字,主要用于错误处理资源清理。它们通常一起使用,特别是在处理panic(运行时崩溃)时,确保程序不会直接崩溃,而是能够优雅地恢复并继续执行。


1. defer 关键字

作用

defer 用于延迟执行一个函数调用,通常用于:

  • 资源释放(如关闭文件、数据库连接、解锁等)。
  • 确保某些操作在函数返回前执行(即使函数提前返回或发生 panic)。

特点

  1. 延迟执行defer 语句不会立即执行,而是等到包含它的函数返回前才执行。
  2. 后进先出(LIFO):如果有多个 defer,它们会按照逆序执行(类似栈结构)。
  3. 即使 panic 也会执行defer 语句在函数 panic 时仍然会执行,这使得它非常适合用于错误恢复

示例

package mainimport "fmt"func main() {defer fmt.Println("1")  // 最后执行defer fmt.Println("2")  // 第二个执行fmt.Println("3")        // 最先执行
}

输出:

3
2
1

说明:

  • defer 语句是延迟执行的,所以 fmt.Println("3") 最先执行。
  • 两个 defer 按照逆序执行,所以 21 之前打印。

2. recover 关键字

作用

recover 用于捕获 panic,防止程序直接崩溃,并允许程序继续执行。

特点

  1. 只能在 defer 函数中使用recover 必须在 defer 调用的函数中使用,否则无效。
  2. 捕获 panic:如果程序发生 panic,recover 可以捕获它,并返回 panic 传递的值。
  3. 不会终止程序:如果 recover 成功捕获 panic,程序不会崩溃,而是继续执行。

示例

package mainimport "fmt"func main() {defer func() {if r := recover(); r != nil {  // 捕获 panicfmt.Println("捕获到 panic:", r)}}()panic("发生了一个严重错误!")  // 触发 panicfmt.Println("这行不会执行")    // 不会执行
}

输出:

捕获到 panic: 发生了一个严重错误!

说明:

  • panic 会导致程序崩溃,但 defer 中的 recover 捕获了它,程序不会退出。
  • fmt.Println("这行不会执行") 不会执行,因为 panic 已经发生,但 recover 阻止了程序崩溃。

3. defer + recover 组合使用

典型场景

  • 防止 panic 导致程序崩溃(如 HTTP 服务器、数据库操作等)。
  • 资源清理(如关闭文件、解锁等),即使发生 panic 也要确保资源释放。

示例:防止 panic 崩溃

package mainimport "fmt"func safeDivide(a, b int) (result int) {defer func() {if r := recover(); r != nil {  // 捕获 panicfmt.Println("捕获到 panic:", r)result = 0  // 返回默认值}}()return a / b  // 如果 b=0,会 panic
}func main() {fmt.Println(safeDivide(10, 2))  // 正常情况fmt.Println(safeDivide(10, 0))  // 除零 panic
}

输出:

5
捕获到 panic: runtime error: integer divide by zero
0

说明:

  • safeDivide 函数在 defer 中使用 recover 捕获 panic。
  • 如果 b=0 导致 panic,recover 会捕获它,并返回 0 而不是让程序崩溃。

示例:文件操作(确保文件关闭)

package mainimport ("fmt""os"
)func readFile(filename string) {file, err := os.Open(filename)if err != nil {fmt.Println("打开文件失败:", err)return}defer file.Close()  // 确保文件关闭,即使发生 panic// 模拟 panicpanic("读取文件时发生错误!")// 正常情况下读取文件内容// buf := make([]byte, 1024)// file.Read(buf)// fmt.Println(string(buf))
}func main() {readFile("example.txt")fmt.Println("程序继续执行...")
}

输出:

打开文件失败: open example.txt: no such file or directory
程序继续执行...

说明:

  • 即使 panic 发生,defer file.Close() 仍然会执行,确保文件被关闭。
  • 程序不会崩溃,而是继续执行 fmt.Println("程序继续执行...")

4. 总结

关键字

作用

特点

defer

延迟执行函数调用

后进先出(LIFO),即使 panic 也会执行

recover

捕获 panic

只能在 defer

中使用,防止程序崩溃

defer + recover

错误恢复

确保资源释放,防止 panic 导致程序崩溃

最佳实践

  1. 资源清理(如文件、数据库连接、锁)→ defer
  2. 防止 panic 崩溃(如 HTTP 服务器、关键计算)→ defer + recover
  3. 避免滥用 recoverrecover 应该只用于预期内的 panic,而不是掩盖所有错误(如应该用 error 返回值处理的错误)。

这样,你就可以在 Go 中优雅地处理错误和资源管理了! 🚀

http://www.dtcms.com/a/301572.html

相关文章:

  • Windows 11 安装 jdk 8
  • Cgroup 控制组学习(三)在容器中使用 CGroups
  • goland编写go语言导入自定义包出现: package xxx is not in GOROOT (/xxx/xxx) 的解决方案
  • 微服务架构面试题
  • PiscCode使用OpenCV实现漂浮方块特效
  • 编程语言Java——核心技术篇(五)IO流:数据洪流中的航道设计
  • 仓库管理系统-2-后端之基于继承基类的方式实现增删改查
  • 【RL第三篇】REINFORCE Leave-One-Out(RLOO)算法(基于留一法的REINFORCE策略梯度算法)
  • RK3568基于mpp实现硬解码(一):mpp库的编译使用
  • [每周一更]-(第151期):Go语言中的Map、Slice、Array和Hash原理详解
  • 博士招生 | 香港大学 招收人工智能和网络安全方向 博士生
  • 7.27 状态机dp|质数线性筛|序列化树
  • Linux网络-------2.应⽤层⾃定义协议与序列化
  • SpringBoot实现Serverless:手撸一个本地函数计算引擎
  • mcu trace工具调研
  • elasticsearch 倒排索引原理详解
  • SpringBoot3整合Redis
  • 零基础学习性能测试第五章:性能瓶颈分析与调优-网络资源瓶颈分析与优化建议
  • Python调用大模型api并部署到前端的主流技术栈以及具体框架对比
  • 【牛客网C语言刷题合集】(四)
  • Java类加载器与双亲委派模型
  • n8n “Run Once for All Items“和“Run Once for Each Item“区别
  • 深度学习中的计算图与自动微分原理:静态图与动态图的实现差异
  • sd Function 学习笔记
  • BeautifulSoup 使用详解与实战示例
  • WAIC 2025 热点解读:如何构建 AI 时代的“视频神经中枢”?
  • WordPress 网站中的“mu-plugins”隐藏后门
  • [每周一更]-(第152期):Go中的CAS(Compare-And-Swap)锁原理详解
  • Java面试宝典:MySQL性能优化
  • ES6模块详解:核心语法与最佳实践