panic是程序级熔断,error是业务级信号;预见到的失败(如文件打开失败、http超时)必须用error显式处理,仅初始化致命错误、内部断言失败或运行时不可恢复错误才允许panic。

panic 是程序级熔断,error 是业务级信号——两者根本不在一个处理层级上。
什么时候该用 error 而不是 panic
绝大多数你预见到的失败场景,都该走 error 流程。比如打开文件失败、HTTP 请求超时、JSON 解析出错、数据库查不到记录。这些不是“程序坏了”,而是“事情没办成”,调用方有充分理由去重试、降级或返回友好提示。
-
error必须被显式检查:if err != nil,不检查就丢弃(用_)也得是明确决策 - 函数签名里带
error返回值,是向所有调用者声明:“这事可能失败,请做好准备” - 频繁触发
panic来替代error,会让测试变脆弱、日志淹没真实问题、监控误报率飙升
哪些情况才允许触发 panic
panic 不是错误处理手段,而是程序自毁开关。它只适用于当前 goroutine 已无法维持基本一致性,继续执行只会让状态更糟。
- 初始化阶段致命失败:比如配置解析后发现
DBURL为空且无默认值,服务根本没法启动 - 内部断言失败:比如某个函数文档承诺“输入非空切片”,结果收到
nil,说明上游逻辑已失控 - 运行时不可恢复错误:如
slice越界、nil指针解引用、类型断言失败——这些本不该出现在生产代码里 - 注意:
recover只能捕获当前 goroutine 的panic,跨 goroutine 的panic会静默退出,无法被外层defer捕获
recover 的真实能力边界
recover 不是 try-catch,它不能让你“继续刚才那行”。它只是把崩溃前的最后一口气接住,给你一次清理和记录的机会。
-
recover()必须写在defer函数体内,且defer语句必须出现在panic之前,否则注册不上 - 一旦
recover成功,原panic发生点之后的所有语句(包括同函数内后续代码)全部跳过 - 副作用不会回滚:如果
panic前已往 channel 发送数据、修改了全局 map、写入了临时文件,recover后这些操作依然生效 - 不要在
recover分支里尝试“修复并重试”,而应记录堆栈 + 返回 fallback 响应 + 显式退出或返回安全值
真正容易被忽略的是:很多开发者把 panic 当作快速退出的捷径,却忘了它绕过了所有正常的错误传播路径。当你在 HTTP handler 里 panic("user not found"),前端收到的是 500,而不是 404;日志里没有上下文 ID,监控系统抓不到业务维度的失败率。这种混淆,比不处理错误更危险。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











