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

panic、defer、recover

panic、defer、recover

panic定义

panic是Go语言的一个内置函数,用于引发运行时的错误,当程序运行到某个不可恢复的错误状态时,可以调用panic函数,panic会立即停止当前函数的正常执行流程,然后逐级执行函数的defer语句(如果有),最后程序退出并输出错误信息(除非在上层调用recover捕获)。

panic("无法恢复的异常")
  • 相当于其他语言的throw异常(但Go没有try/catch)
  • 一旦触发panic:
    1. 当前函数停止执行;
    2. 执行当前goroutine的所有延迟调用(defer);
    3. 继续向上回溯调用栈,直到:
      1. 找到revocer()
      2. 或者回溯到顶层,程序退出

defer

defer语句用于安排函数调用在函数退出时执行,defer通常用于确保某个操作在函数执行结束后发生,无论函数是否发生panic。defer语句经常被用于处理资源释放(如文件关闭、连接关闭)或者错误处理(通过recover函数)。

func demo() {defer fmt.Println("defer 输出")
}

recover

recover是一个内建函数,用于从panic中恢复,当panic函数被调用时,它会停止当前函数的执行,并且执行在该函数使用defer关键字延迟的函数,然后返回一个非nil值,如果在defer延迟的函数中调用了recover函数,程序会从panic的状态中恢复过来,继续正常执行后续代码。

recover 可以中止 panic 造成的程序崩溃。 它是一个只能在 defer 中发挥作用的函数,在其他作用域中调用不会发挥作用。

func demo() {defer func() {if r := recover(); r != nil {fmt.Println("recover from panic", r)}}
}

panic的使用场景

Go官方推荐:panic只用于无法恢复的错误

常见场景
  • 程序内部逻辑出现严重错误

逻辑不可能发生但发生了,例如数据结构被破坏

if node == nil {panic("unexpected nil node: tree structure corrupted")
}
  • 初始化阶段的不可恢复错误

比如配置文件缺失,数据库连接参数错误

func init() {if os.Getenv("CONF_PATH") == "" {panic("missing CONFIG_PATH environment variable")}
}
  • 开发调试阶段

用来快速中断程序,并暴露错误(生产环境替换为错误处理)

使用示范

  • 示范1
package mainimport "fmt"func main() {fmt.Println("Start")panic("something went wrong")fmt.Println("This will never be printed")
}Start
panic: something went wronggoroutine 1 [running]:
main.main()/path/to/main.go:7 +0x39
exit status 2
  • 示范2: panic +defer
package mainimport "fmt"func main() {defer fmt.Println("defer 1: will run before panic exits")defer fmt.Println("defer 2: also runs")fmt.Println("Start")panic("unexpected error")fmt.Println("Never reached")
}Start
defer 2: also runs
defer 1: will run before panic exits
panic: unexpected error
...
  • 示范3:panic+recover

recover()必须在defer中调用才有效,否则捕获不到panic。

package mainimport "fmt"func mayPanic() {panic("boom!")
}func main() {defer func() {if r := recover(); r != nil {fmt.Println("Recovered from panic:", r)}}()mayPanic()fmt.Println("Program continues after recover")
}Recovered from panic: boom!
Program continues after recover

panic使用注意事项

  1. 不要用panic当普通错误处理

Go倡导 error return + if err!=nil 处理可恢复错误

panic仅在"无路可走"的时候使用

  1. panic只会影响当前的goroutine

其他goroutine会继续运行,除非主goroutine崩溃退出整个进程。

  1. recover不能跨goroutine捕获

要在panic发生的同一个goroutine中用recover

  1. panic发生时defer仍会执行

这也是释放资源、关闭文件的最后机会

官方推荐的panic使用模式

func MustSomething(ok bool) {if !ok {panic("something is wrong")}
}

命名规范:带Must前缀的函数通常表示会panic(例如 template.Must())。

这种方式明确告诉调用者:

不用检查返回值,因为失败直接panic。

调用方可以选择用recover捕获。

Go panic运行流程

┌──────────────────────┐
│  正常执行 main()      │
└─────────┬────────────┘│▼触发 panic("error")│▼
┌──────────────────────┐
│ 停止当前函数执行      │
│(后续代码不再运行)   │
└─────────┬────────────┘│▼
依次执行已注册的 defer(LIFO 顺序)│▼
在 defer 中调用 recover() 吗?┌─┴───┐│  是 │──► 捕获 panic 值 → 正常返回└──┬──┘│否▼回溯到上层调用函数│▼
上层调用有 defer + recover 吗?┌─┴───┐│  是 │──► 捕获 panic 值 → 正常返回└──┬──┘│否▼重复执行:执行 defer → 回溯│▼
到达最顶层仍未 recover?│▼程序崩溃,打印 panic 堆栈
http://www.sczhlp.com/news/6809/

相关文章:

  • 使用JDK 自带jstack工具排查问题 - xiao-jie
  • 嵌入式软件架构漫谈
  • 数据服务_数据服务项目开发总结
  • 数据集_具身智能数据集了解
  • 深入解析:各种信号分解、模态分解方法合集【MATLAB实现】
  • 小样本学习在语言理解任务中的突破
  • 枚举-熄灯问题
  • 乞丐哥的私房菜(Windows OpenCV篇——Image Processing 节 之 Adding borders to your images 给你的图像加上边框)十二 - 指南
  • GIST 复发风险预测升级!影像 + 病理 + 临床多模态模型来了,精准度再突破
  • 应聘记录
  • 2025 暑假集训 Day2
  • 2025 暑假集训 Day1
  • 关于在php和html混写
  • 列出文件下所有文件并生成带有下载链接的li标签 需要在ol标签内使用
  • 8月6日
  • Luogu P5062 [Ynoi Easy Round 2014] 在太阳西斜的这个世界里 题解
  • C++ String.format()的详细用法
  • manacher
  • $\text{Linux}$ 网络编程
  • 【JavaSE】BigDecimal是不可变对象(immutable)
  • zerotier进行内网穿透
  • etcd对boltdb的使用和改进
  • The Subway
  • 8月6日随笔
  • 微软藏得太深! 99%的人不知道的免费录制4K视频隐藏功能 超好用!
  • 《LabVIEW 2025 安装全流程图解:新手也能一次搞定!》
  • bsc 静态节点部署 - 若
  • arduino开发你好小智(2)外设led,温湿度传感器,舵机设备控制 - MKT
  • U++第三方库导入
  • Sentinel与OpenFeign整合