recover() 返回 interface{},需类型判断或 fmt.sprintf("%v", r) 安全转换;常见错误是直接断言 string 或 error 导致新 panic;务必用 type switch + default 分支兜底;recover 仅获 panic 参数,无堆栈,需 debug.printstack() 辅助定位。

recover() 返回的是 interface{},不能直接当字符串用,必须做类型判断或安全转换才能拿到可读错误内容。
recover 返回值的类型不确定,直接断言 string 会 panic
常见错误是写 err.(string) 强制转成字符串,但 panic 参数可能是 *runtime.Error、error 接口、int,甚至自定义 struct。一旦类型不匹配,recover() 后再做错误断言会立刻触发新 panic。
- runtime 抛出的 panic(如
index out of range)底层类型未导出,err.(error)也会失败 - 第三方库可能传入
fmt.Errorf(...),此时是*errors.errorString,不是原始error接口实现 - 最稳妥的日志方式是
fmt.Sprintf("%v", r)—— 它能安全处理任意类型
如何安全提取 panic 内容并转为 error
若需统一转成 error 类型用于返回或日志结构化,推荐用类型 switch + fallback:
诊断并恢复通过 SSH 隧道连接的 OpenClaw 节点。用于解决配对必需错误、隧道冲突、远程端点错误以及 SSH 目标配置错误等问题。
if r := recover(); r != nil {
var err error
switch x := r.(type) {
case string:
err = errors.New(x)
case error:
err = x
default:
err = fmt.Errorf("panic: %v", x)
}
log.Printf("panic captured: %v", err)
}
- 不要漏掉
default分支,这是兜底关键 - 避免对
x做二次解引用(比如x.Error()),某些类型没有该方法 - HTTP handler 中建议用
fmt.Sprintf("%v", r)直接塞进 JSON 错误响应体,省去类型判断开销
recover 捕获不到 panic 的常见原因
即使写了 recover(),也常因调用位置不对而返回 nil:
-
recover()不在defer函数体内 —— 直接写在函数体里永远无效 - panic 发生在其他 goroutine,当前 defer 所在 goroutine 并未 panic
- panic 已被更内层的
recover()捕获过,外层再调用返回nil - defer 函数本身没执行到(比如 panic 在 defer 注册前就发生了)
真正容易被忽略的是:recover 拿到的值只是 panic 的“参数”,它不包含堆栈。想看 panic 发生在哪一行,必须配合 debug.PrintStack() 或在 recover 分支里手动记录 runtime.Caller(0)。否则只看到 "index out of range" 这种信息,根本定位不到具体代码位置。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










