recover必须写在defer匿名函数中,直接调用或在if分支中使用均无效;需在可能panic的代码前注册defer func(){recover()},且panic后应立即记录栈信息并return,不可继续解析或访问受损状态。

recover 必须写在 defer 匿名函数里,否则永远返回 nil
数据解析失败时想用 recover 拦住 panic,第一步就常踩坑:把 recover() 直接写在函数体里,或者塞进普通 if 分支、提前 return 之前。这种写法不会捕获任何 panic,recover() 总是返回 nil,程序照常崩溃。
真正有效的写法只有一种:defer func() { if r := recover(); r != nil { /* 处理 */ } }()。这个 defer 必须在可能触发 panic 的解析代码之前注册——比如你在调用 json.Unmarshal 或递归解析嵌套结构前,就得先把这行 defer 写上。
- 错误示范:
recover()单独一行、或在if err != nil块里调用 → 无效 - 正确顺序:先
defer func() { recover() },再json.Unmarshal(...) - 多个
defer时,只有 panic 触发后、函数退出前正在执行的那个defer里的recover()才可能生效
panic 后不能继续解析逻辑,状态已不可信
数据解析中发生 panic(比如切片越界、空指针解引用、map 并发读写),说明内存或结构已处于损坏状态。recover() 只是让 goroutine 不退出,它不修复变量、不回滚中间结果、也不续上 panic 那行之后的代码。如果你在 recover() 后继续调用 parseNextField() 或往刚 panic 过的 map 里写数据,大概率会二次 panic。
安全做法是:记录完 panic 信息后立刻 return,别往下走。
立即学习“go语言免费学习笔记(深入)”;
文件删除恢复功能 v0.8.0:删除前自动备份文件(存至 `delete_backup/YYYYMMDDHHMM/` 目录),支持从备份中恢复、通过清单(manifest)搜索。具备 SHA256 完整性校验、路径遍历防护及工作区根目录(workspace-root)访问限制。支持自动清理 7 天 / 30 天前的备份。 **v0.8.0:新增 `workspace_cleaner` —— 支持定时清理临时文件,并在删除前自动执行备份。** **v0.7.0:`allowed_roots` 默认值
- 别在
recover()后继续访问刚出错的 slice、map 或 struct 字段 - 别调用可能再次 panic 的函数(如
close(ch)、fmt.Sprintf对 nil 接口操作) - 资源清理应放在
defer链里,而不是recover()后的业务分支中
要看到哪一行 panic,必须立即调用 debug.Stack()
recover() 只返回 panic 的值(比如 "invalid character" 或 &json.SyntaxError{...}),不带位置信息。光靠这个很难定位问题。你需要在 recover() 后**立刻**调用 runtime/debug.Stack() 获取当前 goroutine 的完整调用栈。
注意:debug.Stack() 返回的是 []byte,得转成 string 才能打印;而且它必须在 recover() 后马上执行,否则后续 defer 或日志语句可能污染栈帧。
- 推荐写法:
log.Printf("parse panic: %v\n%s", r, string(debug.Stack())) - 生产环境建议限制长度:
debug.Stack()[:min(len(buf), 4096)],防日志爆炸 - 别用
fmt.PrintStack()—— 它直接输出到stderr,无法控制格式和目标
子 goroutine 的 panic 必须各自防护,主流程拦不住
如果解析逻辑跑在独立 goroutine 里(比如从 channel 读数据并异步解析),主 goroutine 上写的 defer + recover 完全无效。每个 goroutine 的 panic 是隔离的,必须在启动它的那一层自己包一层 defer func() { recover() }()。
常见场景如 HTTP handler、worker 循环、流式解析器,都得在 goroutine 内部做防护,而不是指望外层统一兜底。
- HTTP handler 示例:
go func() { defer func(){...}(); parseJSON(req.Body) }() - 不要依赖
sync.WaitGroup等待子 goroutine 结束来“捕获”它的 panic —— 等不到,它已经崩了 - 单生产者 + 无并发读写的通道关闭可配合
recover,但这是极少数安全场景,别泛化
解析失败时用 recover 的本质,不是为了“继续干活”,而是为了不让一个坏数据拖垮整个 goroutine。真正容易被忽略的点是:panic 后的状态不可信,而每个 goroutine 都得自己负责自己的防线 —— 没有全局开关,也没有父级代劳。

















