Go 错误处理的方式与技巧
Go 语言采用显式错误处理机制,核心思想是将错误视为普通值而非异常。以下是主要方式和优化技巧:
一、基础处理方式
-
错误返回值
Go 函数通常返回(result, error)对,调用方必须显式检查:func ReadFile(filename string) ([]byte, error) { data, err := os.ReadFile(filename) if err != nil { return nil, err // 返回原始错误 } return data, nil } -
错误类型接口
所有错误类型实现error接口:type error interface { Error() string }
二、进阶技巧
-
自定义错误类型
添加额外上下文信息:type PathError struct { Path string Reason string } func (e *PathError) Error() string { return fmt.Sprintf("path: %s, reason: %s", e.Path, e.Reason) } // 使用示例 return nil, &PathError{Path: filename, Reason: "permission denied"} -
错误包装(Go 1.13+)
使用%w保留原始错误链:if err != nil { return fmt.Errorf("read failed: %w", err) // 包装原始错误 } -
错误检查工具
errors.Is:检查特定错误类型if errors.Is(err, os.ErrNotExist) { // 处理文件不存在 }errors.As:提取自定义错误var perr *PathError if errors.As(err, &perr) { fmt.Println("Failed path:", perr.Path) }
三、最佳实践
-
避免嵌套地狱
使用提前返回减少缩进:func Process() error { if err := step1(); err != nil { return err } if err := step2(); err != nil { return err } return step3() } -
错误上下文增强
在关键位置添加额外信息:if err := db.Query(); err != nil { return fmt.Errorf("query user %d: %w", userID, err) } -
处理第三方库错误
封装外部库错误,避免依赖泄漏:// 定义项目专属错误类型 var ErrDBConnection = errors.New("database connection error") func ConnectDB() error { if err := thirdparty.Connect(); err != nil { return fmt.Errorf("%w: %v", ErrDBConnection, err) } return nil } -
选择性 panic
仅在启动阶段不可恢复错误时使用:func MustLoadConfig() Config { cfg, err := LoadConfig() if err != nil { panic("config load failed: " + err.Error()) } return cfg }
四、错误处理模式对比
| 模式 | 适用场景 | 示例 |
|---|---|---|
| 直接返回错误 | 简单操作 | return err |
| 错误包装 | 需要添加上下文 | fmt.Errorf("...%w", err) |
| 自定义错误类型 | 需要结构化错误信息 | &CustomError{Field: value} |
errors.Is/As | 精确错误类型匹配 | errors.Is(err, io.EOF) |
关键原则:
- 每个可能失败的操作都返回
error- 在调用层级顶部统一处理日志/告警
- 避免忽略错误(
_ = func()需显式标注)- 文档注明函数可能返回的错误类型

被折叠的 条评论
为什么被折叠?



