Go Errors 错误处理

简介: Go Errors 错误处理

Golang 中的 error 是一个内置的特殊的接口类型:

type error interface {
    Error()  string
}

在 Go 1.13 版本之前,有关 error 的方法只有两个:

  • errors.New :  
func New(text string) error
  • fmt.Errorf :
func Errorf(format string, a ...interface{}) error

这两个方法都是用来生成一个新的 error 类型的数据。



01
1.13 版本之前的错误处理


最常见的,判断是否为 nil :

if err != nil {
    // something went wrong
}

判断是否为某个特定的错误:

var ErrNotFound = errors.New("not found")
if err == ErrNotFound {
    // something wasn't found
}

error 是一个带有 Error 方法的接口类型,这意味着你可以自己去实现这个接口:

type NotFoundError struct {
    Name string
}
func (e *NotFoundError) Error() string { 
    return e.Name + ": not found" 
}
if e, ok := err.(*NotFoundError); ok {
    // e.Name wasn't found
}

处理错误的时候我们通常会添加一些额外的信息,记录错误的上下文以便于后续排查:

if err != nil {
    return fmt.Errorf("错误上下文 %v: %v", name, err)
}

fmt.Errorf 方法会创建一个包含有原始错误文本信息的新的 error ,但是与原始错误之间是没有任何关联的。


然而我们有时候是需要保留这种关联性的,这时候就需要我们自己去定义一个包含有原始错误的新的错误类型,比如自定义一个 QueryError :

type QueryError struct {
    Query string
    Err   error  // 与原始错误关联
}

然后可以判断这个原始错误是否为某个特定的错误,比如 ErrPermission :

if e, ok := err.(*QueryError); ok && e.Err == ErrPermission {
    // query failed because of a permission problem
}

写到这里,你可以发现对于错误的关联嵌套情况处理起来是比较麻烦的,而 Go 1.13 版本对此做了改进。


02


1.13 版本之后的错误处理


首先需要说明的是,Go 是向后兼容的,上文中的 1.13 版本之前的用法完全可以继续使用。


1.13 版本的改进是:

  • 新增方法 errors.Unwrap :
func Unwrap(err error) error
  • 新增方法 errors.Is :
func Is(err, target error) bool
  • 新增方法 errors.As :
func As(err error, target interface{}) bool
  • fmt.Errorf 方法新增了 %w 格式化动词,返回的 error 自动实现了 Unwrap 方法。


下面进行详细说明。


对于错误嵌套的情况,Unwrap 方法可以用来返回某个错误所包含的底层错误,例如 e1 包含了 e2 ,这里 Unwrap e1 就可以得到 e2 。Unwrap 支持链式调用(处理错误的多层嵌套)。


使用 errors.Iserrors.As 方法检查错误:

  • errors.Is 方法检查值:
if errors.Is(err, ErrNotFound) {
    // something wasn't found
}
  • errors.As 方法检查特定错误类型:
var e *QueryError
if errors.As(err, &e) {
    // err is a *QueryError, and e is set to the error's value
}

errors.Is 方法会对嵌套的情况展开判断,这意味着:

if e, ok := err.(*QueryError); ok && e.Err == ErrPermission {
    // query failed because of a permission problem
}

可以直接简写为:

if errors.Is(err, ErrPermission) {
    // err, or some error that it wraps, is a permission problem
}

fmt.Errorf 方法通过 %w 包装错误:

if err != nil { 
    return fmt.Errorf("错误上下文 %v: %v", name, err)
}

上面通过 %v 是直接返回一个与原始错误无法关联的新的错误。

我们使用 %w 就可以进行关联了:

if err != nil {
    // Return an error which unwraps to err.
    return fmt.Errorf("错误上下文 %v: %w", name, err)
}

一旦使用 %w 进行了关联,就可以使用 errors.Iserrors.As 方法了:

err := fmt.Errorf("access denied: %w”, ErrPermission)
...
if errors.Is(err, ErrPermission) ...

对于是否包装错误以及如何包装错误并没有统一的答案。


目录
相关文章
|
1月前
|
SQL 安全 数据库连接
《Go 简易速速上手小册》第6章:错误处理和测试(2024 最新版)(上)
《Go 简易速速上手小册》第6章:错误处理和测试(2024 最新版)
51 1
|
1月前
|
Go 开发者
Go语言中的错误处理与异常机制:实践与最佳策略
【2月更文挑战第7天】Go语言以其独特的错误处理机制而闻名,它鼓励显式错误检查而不是依赖于异常。本文将探讨错误处理与异常机制在Go语言中的实际应用,并分享一些最佳实践,帮助开发者编写更加健壮和易于维护的Go代码。
|
1月前
|
存储 Cloud Native 编译器
云原生系列Go语言篇-错误处理
从其它语言转Go最大的挑战之一就是错误处理。对那些习惯了使用异常的开发者,Go采取的方法有些离经叛道。但Go语言使用的方法蕴含着牢不可破的软件工程原理。本章中,我们学习如何在Go中处理错误。我们会学习Go系统中会停止执行的错误处理panic和recover。
47 0
|
8月前
|
前端开发 数据库连接 Go
Go 语言错误处理为什么更推荐使用 pkg/errors 三方库?
Go 语言错误处理为什么更推荐使用 pkg/errors 三方库?
56 0
|
8月前
|
Go 开发者
错误处理不再难!Go语言错误处理完全指南
错误处理不再难!Go语言错误处理完全指南
103 0
|
1月前
|
JSON 测试技术 Go
《Go 简易速速上手小册》第6章:错误处理和测试(2024 最新版)(下)
《Go 简易速速上手小册》第6章:错误处理和测试(2024 最新版)
47 0
|
10天前
|
Go
掌握Go语言:Go语言错误处理,从基础到高级,让你的代码更健壮!(33)
掌握Go语言:Go语言错误处理,从基础到高级,让你的代码更健壮!(33)
|
10天前
|
SQL 数据库连接 Go
掌握Go语言:Go语言精细错误,清晰、高效的错误处理实践(32)
掌握Go语言:Go语言精细错误,清晰、高效的错误处理实践(32)
|
13天前
|
Go
Go 错误处理
Go 错误处理
17 3
|
1月前
|
Go API 开发者
【Go语言专栏】Go语言的错误处理机制
【4月更文挑战第30天】Go语言的错误处理机制简洁强大,错误被视为`error`类型的值。通过`if err != nil`检查错误,使用`log.Fatal`记录并结束程序。错误可被包装以提供上下文信息,通过`Unwrap()`解包找到底层错误。Go 1.13引入的`errors.Is()`、`errors.As()`和改进的`fmt.Errorf()`支持错误链和追踪,助力编写健壮的Go代码。理解并熟练运用这些机制对开发者至关重要。