Go错误处理核心陷阱是忽略、裸传、误判和静默:忽略err埋雷,裸传暴露敏感信息,类型断言被包装破坏,goroutine错误未导出。应记录/转换/传播/终止,用errors.Is/As、errgroup、脱敏返回。

Go 错误处理最常踩的坑,不是不会写 if err != nil,而是写了却没真正“处理”——错误被忽略、被吞掉、被乱包、被裸传,最终让故障在日志里隐身、在生产环境里爆发。
忽略 err 返回值:最隐蔽也最危险的“省事”
用 _ 丢弃错误不是偷懒,是主动埋雷。一旦 os.Open 失败,file 是 nil,后续 file.Read 直接 panic;json.Unmarshal 解析失败却不检查,就拿脏数据往下走。
- 永远别对任何返回
error的函数用_忽略错误 - 哪怕只是记录后继续,也要写明意图:
if err != nil { log.Printf("warn: config load failed, using defaults: %v", err) return defaultConfig } - CI 中可启用
go vet -tags=errorlint或静态检查工具(如errcheck)自动捕获这类遗漏
裸传底层错误:把数据库密码和堆栈全吐给 API 调用方
return db.QueryRow(...) 出错时直接返回 *pq.Error 或 sql.ErrNoRows,前端收到 "pq: password authentication failed for user 'prod_db_admin'" 这类响应,等于把数据库凭据和部署结构暴露出去。
- 业务层必须拦截并重写错误:用
fmt.Errorf("获取用户失败:%w", err)包装,再用errors.Is判断是否为预期错误(如errors.Is(err, sql.ErrNoRows)) - 对外返回的错误信息应脱敏、语义化,例如
"用户不存在",而非原始驱动错误 - 敏感上下文(如 SQL 查询语句、文件路径、token)绝不能出现在最终返回的错误字符串中
滥用类型断言:一包装就失效的“精准判断”
写 if e, ok := err.(*os.PathError); ok 看似精准,但只要上游用了 fmt.Errorf("read failed: %w", err) 或 errors.Wrap,断言立刻失败——因为包装后的错误是 *fmt.wrapError,不是 *os.PathError。
动态WEB网站中的PHP和MySQL详细反映实际程序的需求,仔细地探讨外部数据的验证(例如信用卡卡号的格式)、用户登录以及如何使用模板建立网页的标准外观。动态WEB网站中的PHP和MySQL的内容不仅仅是这些。书中还提到如何串联JavaScript与PHP让用户操作时更快、更方便。还有正确处理用户输入错误的方法,让网站看起来更专业。另外还引入大量来自PEAR外挂函数库的强大功能,对常用的、强大的包
立即学习“go语言免费学习笔记(深入)”;
- 优先使用标准检查函数:
os.IsNotExist(err)、os.IsPermission(err)、net.IsTimeout(err) - 必须做类型判断时,用
errors.As替代直接断言:var pathErr *os.PathError if errors.As(err, &pathErr) { log.Printf("路径错误:%s", pathErr.Path) } - 自定义错误类型要支持
errors.Unwrap(),确保包装链可追溯
并发场景下错误静默:goroutine 里的 panic 和 error 全部消失
启动一个 go doSomething(),里面出错只打印日志不通知主流程,结果任务失败了没人知道,定时任务漏跑、消息没发、状态没更新,全靠监控告警“被动发现”。
- 关键并发任务必须有错误出口:用带缓冲的
chan error或errgroup.Group - 推荐组合
context.Context+errgroup:g, ctx := errgroup.WithContext(ctx) g.Go(func() error { return processItem(ctx, item) }) if err := g.Wait(); err != nil { return fmt.Errorf("batch failed: %w", err) } - 永远不要在 goroutine 里只调
log.Fatal或panic——它杀不掉其他 goroutine,也逃不出主流程控制
错误不是异常的替代品,它是 Go 里最普通的值;而“处理错误”的本质,是决定这个值该被记录、转换、传播,还是终止流程——所有反模式,都源于跳过了这个决策过程。









