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

【Go语言基础【14】】defer与异常处理(panic、recover)

文章目录

  • 零、概述
  • 一、defer关键字:延迟执行机制
    • 1. 基本原理
    • 2. defer下变量的作用域
    • 3. 典型应用场景
  • 二、异常处理机制:panic(类java throw)与recover(捕获)
    • 1. panic:触发异常
    • 2. recover:捕获异常
  • 三、defer与recover结合使用
    • 1. 通用异常处理模板
    • 2. 多层调用中的异常传递

零、概述

关键字/函数作用描述
defer延迟执行函数,用于资源释放、日志记录等,按LIFO顺序执行
panic触发异常,终止当前协程正常执行,可显式调用或由运行时错误触发
recoverdefer中捕获panic,恢复程序执行,避免崩溃
执行顺序deferreturnpanic(若未捕获)
最佳实践defer用于资源管理,panic/recover用于不可恢复的严重错误处理

注意事项:

  1. defer的性能影响
    • 每个defer会创建一个栈帧,过多使用可能影响性能(尤其在高频调用的函数中)。
    • 建议仅在必要场景(如资源释放)中使用defer,避免滥用。
  2. panic的合理使用
    • 不建议在业务逻辑中滥用panic,应优先使用多返回值(如(result, error))处理可预期的错误。
    • 推荐场景:处理不可恢复的严重错误(如配置文件缺失、数据库连接失败)。
  3. recover的作用范围
    • recover仅能捕获当前协程的panic,无法跨协程捕获(如其他goroutine中的panic)。
    • 跨协程异常处理需通过通道(channel)传递错误。

 

一、defer关键字:延迟执行机制

1. 基本原理

核心特性

  • 独立的defer栈,延迟执行defer修饰的函数或语句会在当前函数即将退出时执行(包括正常返回、panic异常或提前return)。
  • 栈存储:多个defer按**后进先出(LIFO)**顺序执行,先声明的后执行。
  • 值拷贝defer语句中的参数在声明时立即求值并拷贝,后续修改不影响其值。

 
defer的作用

一般用来做善后操作,例如清理垃圾、释放资源,无论是否报错都执行defer对象。另一方面,defer可以让这些善后操作的语句和开始语句放在一起,无论在可读性上还是安全性上都很有改善,毕竟写完开始语句就可以直接写defer语句,永远也不会忘记关闭、善后等操作

 

执行顺序示例

func deferOrder() {fmt.Println("开始执行")defer fmt.Println(" defer 1") // 压栈顺序:1 → 2 → 3defer fmt.Println(" defer 2")defer fmt.Println(" defer 3")fmt.Println("执行结束") // 先于 defer 执行
}
// 输出:
// 开始执行
// 执行结束
//  defer 3    (最后压栈,最先执行)
//  defer 2
//  defer 1

 

2. defer下变量的作用域

(1)值拷贝机制

func deferValueCopy() {x := 10defer fmt.Println("defer值拷贝:", x) // 声明时拷贝x的值(10)x = 20 // 修改不影响 defer 中的值fmt.Println("修改后x:", x) // 输出:20
}
// defer输出:defer值拷贝:10

(2)闭包引用

func deferClosure() {x := 10defer func() { // 闭包引用外部变量x(非值拷贝)fmt.Println("闭包引用:", x) // 取函数退出时的x值}()x = 20fmt.Println("修改后x:", x) // 输出:20
}
// defer输出:闭包引用:20

defer 延迟执行的是一个匿名函数(闭包),闭包不直接捕获值,而是引用外部变量 x

 

3. 典型应用场景

(1)资源释放(文件、网络连接等)

func readFile(path string) {file, err := os.Open(path)if err != nil {panic(err)}defer file.Close() // 确保文件最终关闭// 处理文件逻辑
}

(2)记录日志或统计耗时

func process() {start := time.Now()defer func() { // 函数结束时打印耗时fmt.Printf("处理耗时:%v\n", time.Since(start))}()// 模拟业务逻辑time.Sleep(1 * time.Second)
}

(3)错误处理中的资源回滚

func transaction() {db, err := openDB()if err != nil {panic(err)}defer db.Rollback() // 事务失败时回滚(需配合 recover)// 执行数据库操作db.Commit() // 成功则提交
}

 

二、异常处理机制:panic(类java throw)与recover(捕获)

1. panic:触发异常

核心作用:

当程序遇到致命错误(如空指针解引用、除数为零)时,panic会中断当前协程的正常执行,并逐层向上抛出异常,最终导致程序崩溃(除非被recover捕获)。

触发时机:

显式调用:主动调用panic(“错误信息”)触发异常(如业务逻辑错误)。
隐式触发:Go 运行时自动抛出(如内存越界、类型断言失败)。

示例:

显式panicfunc divide(a, b int) int {if b == 0 {panic("除数不能为零") // 触发异常}return a / b
}
func main() {divide(10, 0) // 程序崩溃,输出panic信息
}**运行时panic示例**func runtimePanic() {var ptr *int // nil指针fmt.Println(*ptr) // 运行时panic: invalid memory address
}

 

2. recover:捕获异常

作用:在defer函数中调用recover(),捕获当前协程的panic并恢复执行。

注意:

  • 仅在defer修饰的函数中有效,其他位置调用返回nil
  • 捕获后可继续执行defer函数,但当前函数会立即退出,后续代码不执行。
正确用法:
func safeDivide(a, b int) {defer func() {if err := recover(); err != nil { // 捕获panicfmt.Println("捕获异常:", err) // 输出:捕获异常:除数不能为零}}()if b == 0 {panic("除数不能为零") // 触发异常,被defer捕获}fmt.Println(a / b)
}
func main() {safeDivide(10, 0) // 正常执行,不崩溃
}错误用法:
func wrongRecover() {recover() // 非defer中调用,无效panic("测试") // 未捕获,程序崩溃
}

 

三、defer与recover结合使用

1. 通用异常处理模板

func protect(fn func()) { // 保护任意函数防止panicdefer func() {if err := recover(); err != nil {fmt.Println("全局异常处理:", err)}}()fn() // 执行可能panic的函数
}
func main() {protect(func() {panic("业务逻辑异常") // 被保护函数捕获})
}

2. 多层调用中的异常传递

func level3() {panic("level3 panic") // 触发panic
}
func level2() {level3() // 传递panic
}
func level1() {defer func() {if err := recover(); err != nil {fmt.Println("在level1捕获:", err) // 捕获level3的panic}}()level2() // 调用下层函数
}
func main() {level1() // 输出:在level1捕获:level3 panic
}

 

相关文章:

  • 【HarmonyOS 5】拍摄美化开发实践介绍以及详细案例
  • 关于datetime获取时间的问题
  • n8n + AI Agent:AI 自动化生成测试用例并支持导出 Excel
  • 洛谷P12170 [蓝桥杯 2025 省 Python B] 攻击次数
  • PLC有脉冲输出,但伺服电机无法旋转
  • 数组名作为函数参数详解 —— 指针退化及遍历应用示例
  • 一款“短小精悍的”手机录屏软件
  • Linux与Windows切换使用Obsidian,出现 unexplained changes 问题的解决
  • Postman测试学习(1)
  • GPU集群故障分析:大型AI训练中的硬件问题与影响
  • frida简介及环境搭建
  • 「完整」AI文档库 | 5月4日发布,东吴证券:《AI Agent深度二:2025 Agent元年,AI从L2向L3发展》
  • C# 关于CS0433错误的解决方法
  • c++ 单例模式
  • Qwen 大模型-对话模板中system与user的区别解析
  • 孙溟㠭浅析清朝“徽派”篆刻
  • 抗辐照MCU在卫星载荷电机控制器中的实践探索
  • Doris 数据库深度解析:架构、原理与实战应用
  • 自动驾驶---SD图导航的规划策略
  • 【氧化镓】HTFB应力对β - Ga2O3 SBD的影响
  • 网站建设服务器百度云/苏州seo服务
  • 如何 html5 网站/男生最喜欢的浏览器
  • 移动端 pc网站开发/qq推广软件
  • 郑州网站建设seo优化/建设网站推广
  • 怎么建立自己的个人网站/什么是网络营销策略
  • 网站整合营销建设/网络推广都有哪些平台