直接回答:panic 触发后,运行时沿当前 goroutine 的调用栈逐帧执行已注册的 defer(LIFO),展开完毕后进程退出并打印调用栈。recover 的作用是中止展开:它在 goroutine 处于 panicking 状态时取出 panic 值、恢复正常执行。展开阶段执行的唯一用户代码就是 defer,因此 recover 只有在 defer 函数中直接调用才有效,其它位置调用只会得到 nil。惯用写法是在 defer 匿名函数里用 recover 把 panic 转成命名返回值 err。

实践要点:其一,recover 管不到别的 goroutine,子 goroutine panic 整个进程照死,每个 goroutine 边界(handler、worker 池)都要自己 recover。其二,Go 1.21 起 panic(nil) 会被改写,recover 得到 *runtime.PanicNilError 而非 nil。其三,panic/recover 是兜底而非流程控制,业务分支用 error;典型用法是 HTTP 中间件统一 recover、记日志、返回 500。

追问方向:runtime.Goexit 与 panic 展开有何异同?defer 在 Go 1.14 后如何优化?(约 579 字)