Go错误处理最佳实践从error到panic-recover的完整指南
文章导语
错误处理是Go的"招牌特性"------没有try-catch,只有if err != nil。但很多人只会机械地返回error,不理解错误包装、错误链、哨兵错误等进阶模式。
一、错误包装(Wrapping)
go
// Go 1.13+错误包装
func GetUser(id int) (*User, error) {
user, err := db.FindUser(id)
if err != nil {
return nil, fmt.Errorf("获取用户失败 id=%d: %w", id, err)
}
return user, nil
}
// 错误链检查
if errors.Is(err, sql.ErrNoRows) {
// 用户不存在
}
var targetErr *ValidationError
if errors.As(err, &targetErr) {
// 提取具体错误类型
}
二、错误处理模式
go
// 哨兵错误
var ErrNotFound = errors.New("not found")
// 自定义错误类型
type ValidationError struct {
Field string
Msg string
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("%s: %s", e.Field, e.Msg)
}
// defer错误处理
func CopyFile(dst, src string) (err error) {
r, err := os.Open(src)
if err != nil { return }
defer r.Close()
w, err := os.Create(dst)
if err != nil { return }
defer func() {
w.Close()
if err != nil {
os.Remove(dst)
}
}()
_, err = io.Copy(w, r)
return
}
三、全文总结
%w包装错误链,errors.Is/As检查错误链,哨兵错误定义公开错误常量,自定义错误类型携带上下文字段。
参考文献
- Go Blog - Working with Errors in Go 1.13
- Go errors包文档
- Dave Cheney - Don't just check errors