

新闻资讯
技术学院Go错误处理核心是显式处理、保留错误链、避免panic滥用:必须检查err并分流,用%w封装上下文,defer前确保resp非空,遵循“error is value”哲学。
Go 的错误处理不是“加个 if err != nil 就完事”,真正踩坑的地方,往往藏在错误被忽略、被掩盖、被错误传播的瞬间。
err,或检查后不处理这是最基础也最致命的误区。Go 明确要求调用者显式处理错误,但新手常写成:
file, _ := os.Open("config.json") // 直接丢弃 err
json.NewDecoder(file).Decode(&cfg) // file 可能是 nil,panic 风险
一旦 os.Open 失败,file 为 nil,后续操作直接 panic。正确做法必须检查并分流:
return nil, err),让上层决定是否重试或降级_,且需注释说明原因panic 替代错误返回
把本该由业务逻辑处理的可恢复错误(如参数校验失败、HTTP 400、数据库约束冲突)扔给 panic,会导致:
除非是启动阶段强依赖不可用(如配置加载失败、端口被占),否则一律用 error 返回。HTTP handler 中应统一用中间件 recover panic 并转为 500 响应,而非主动 panic。
fmt.Errorf 或 errors.Join 封装底层函数返回了清晰错误(如 "no such file"),但上层只简单返回 err,丢失调用路径信息:
func LoadConfig() error {
f, err := os.Open("config.yaml")
if err != nil {
return err // ❌ 丢失 "LoadConfig called here" 上下文
}
defer f.Close()
return yaml.NewDecoder(f).Decode(&cfg)
}
应该用带上下文的封装:
return fmt.Errorf("load config: %w", err) —— 保留原始错误并添加前缀return errors.Join(err1, err2) —— 合并多个并行错误(如批量调用)fmt.Errorf("load config: %s", err.Error()) —— 破坏错误链,errors.Is/As 失效HTTP 客户端错误处理中高频雷区:
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close() // ❌ 若 err != nil,resp 可能为 nil,panic
必须确保 resp 非空才 defer 关闭:
if err != nil { return err } 后再 defer resp.Body.Close()
resp,再 defer(尤其在自定义 http.Client 场景)io.ReadCloser(包括 resp.Body)都必须关闭,否则连接泄露错误处理最难的部分,从来不是语法,而是判断“这个错误到底该谁负责、该不该继续、该不该暴露给用户”。多一层 fmt.Errorf,少一次 panic,晚一秒 defer——这些细节能让线上问题从“查三天”变成“一眼定位”。