Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Go Errors 错误处理

Go Errors 错误处理

作者头像
凌虚
发布于 2020-07-19 15:40:55
发布于 2020-07-19 15:40:55
1.2K00
代码可运行
举报
运行总次数:0
代码可运行

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type error interface {    Error()  string}

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

  • errors.New :
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func New(text string) error
  • fmt.Errorf :
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func Errorf(format string, a ...interface{}) error

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

01

1.13 版本之前的错误处理

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if err != nil {
    // something went wrong
    }

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var ErrNotFound = errors.New("not found")
if err == ErrNotFound {
    // something wasn't found
    }

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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
         }

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if err != nil {
    return fmt.Errorf("错误上下文 %v: %v", name, err)
    }

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

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type QueryError struct {
    Query string    Err   error  // 与原始错误关联
    }

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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 :
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func Unwrap(err error) error
  • 新增方法 errors.Is :
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func Is(err, target error) bool
  • 新增方法 errors.As :
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func As(err error, target interface{}) bool
  • fmt.Errorf 方法新增了 %w 格式化动词,返回的 error 自动实现了 Unwrap 方法。

下面进行详细说明。

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

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

  • errors.Is 方法检查值:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if errors.Is(err, ErrNotFound) {
    // something wasn't found
    }
  • errors.As 方法检查特定错误类型:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var e *QueryError
if errors.As(err, &e) {
    // err is a *QueryError, and e is set to the error's value
    }

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if e, ok := err.(*QueryError); ok && e.Err == ErrPermission {
    // query failed because of a permission problem
    }

可以直接简写为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if errors.Is(err, ErrPermission) {
    // err, or some error that it wraps, is a permission problem
    }

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if err != nil {
     return fmt.Errorf("错误上下文 %v: %v", name, err)
     }

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

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if err != nil {
    // Return an error which unwraps to err.
    return fmt.Errorf("错误上下文 %v: %w", name, err)
    }

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
err := fmt.Errorf("access denied: %w”, ErrPermission)
...
if errors.Is(err, ErrPermission) ...

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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-10-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Node Python Go全栈开发 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Working with Errors in Go 1.13
Damien Neil and Jonathan Amsterdam 17 October 2019
陌无崖
2020/07/27
5530
Go:温故错误处理
早期Go将错误视为值的处理方式为我们服务良好。尽管标准库对错误的支持很少——只有errors.New和fmt.Errorf函数,这些函数产生的错误只包含一个消息——内置的错误接口允许Go程序员添加他们想要的任何信息。它只需要一个实现了Error方法的类型:
运维开发王义杰
2024/04/25
1430
Go:温故错误处理
Go版本大于1.13,程序里这样做错误处理才地道
之前写过几篇关于 Go 错误处理的文章,发现文章里不少知识点都有点落伍了,比如Go在1.13后对错误处理增加了一些支持,最大的变化就是支持了错误包装(Error Wrapping),以前想要在调用链路的函数里包装错误都是用"github.com/pkg/errors"这个库。
KevinYan
2023/01/03
4190
Go语言中的错误处理机制
在Go语言中,错误处理主要通过内置的error接口实现。error接口是一个内置接口,定义如下:
数字扫地僧
2024/06/20
1330
Go 源码解读|如何用好 errors 库的 errors.Is() 与 errors.As() 方法
快一个月没有更新技术文章了,这段时间投注了较多的时间学习字节的开源项目 Kitex/Hertz ,并维护一些简单的 issue ,有兴趣的同学也可以去了解:
白泽z
2022/12/20
9850
Go语言(golang)新发布的1.13中的Error Wrapping深度分析
Go 1.13发布的功能还有一个值得深入研究的,就是对Error的增强,也是今天我们要分析的 Error Wrapping.
sunsky
2020/08/20
2.1K0
2019年10月17日: Go生态洞察:在Go 1.13中处理错误
🐯 猫头虎博主来啦!今天我们将深入Go 1.13的错误处理新特性。一起探索如何通过增强的标准库功能,更优雅地处理和检查错误。🔍 准备好一起探索Go的错误处理奥秘了吗?
猫头虎
2024/04/09
1480
2019年10月17日: Go生态洞察:在Go 1.13中处理错误
golang错误处理笔记
Go语言中,错误被认为是一种可以预期的结果;而异常则是一种非预期的结果,发生异常可能表示程序中存在 BUG 或发生了其它不可控的问题。
lelezc
2022/12/01
5710
Golang 语言怎么处理错误?
golang 程序大多数是通过 if err != nil 处理错误,在 golang 社区中,有一部分 golang 程序员对此举是持反对观点,他们认为在 golang 代码中存在大量的错误处理代码 if err != nil,使整体代码变得非常不优雅,应该在 golang 中引入其他处理错误的机制,例如 try-catche 或其它此类处理错误的机制。其实,他们忽略了 golang 中一个特别重要的概念,即 errors are values,并且 golang 作者 Rob Pike 也对此问题做出过回应,在 golang 代码中出现重复的错误处理代码 if err != nil,可能是 golang 用户的使用方式有问题。
frank.
2021/03/09
1.4K0
在 Go 中使用错误类型传递上下文信息
在 Go 1.13 版本中,errors 包引入了一种新的错误处理机制,它允许我们在错误中包含更多的上下文信息。通过使用 fmt.Errorf 函数和 %w 格式化动词,我们可以创建一个新的错误,它包含一个原始错误和一个错误消息。然后,我们可以使用 errors.Is 和 errors.As 函数来检查或获取原始错误。
运维开发王义杰
2023/08/10
2830
在 Go 中使用错误类型传递上下文信息
Go 进阶训练营 – 错误处理二:错误定义与处理
哨兵错误,就是定义一些包级别的错误变量,然后在调用的时候外部包可以直接对比变量进行判定,在标准库当中大量的使用了这种方式。例如下方 io 库中定义的错误。
Yuyy
2022/09/13
7280
Go 进阶训练营 – 错误处理二:错误定义与处理
Go Error 嵌套到底是怎么实现的?
这句话应该怎么理解呢?翻译起来挺难的。不过从源码的角度来看,好像更容易理解其背后的含义。
AlwaysBeta
2022/01/14
3180
Go 函数多返回值错误处理与error 类型介绍
error 接口只有一个方法,即 Error() 方法,该方法返回一个描述错误的字符串。这意味着任何实现了 Error() 方法的类型都可以被用作错误类型。通常,Go程序中的函数在遇到错误时会返回一个 error 类型的值,以便调用方可以处理或记录错误信息。
贾维斯Echo
2023/10/23
6520
Go错误处理正确姿势
func Go(f func()){go func(){ // defer recover 捕获panic defer func(){ if err := recover(); err != nil { log.Printf("panic: %+v", err) } }() f()}()}
冬夜先生
2021/09/03
7280
Go语言中的自定义错误类型
定义自定义错误类型后,可以在函数中返回这些错误。以下是一个示例,展示了如何在函数中使用自定义错误类型:
数字扫地僧
2024/07/03
2010
Go错误处理库比较:pkg/errors vs github.com/pkg/errors
pkg/errors是从Go 1.13版本开始,标准库errors增加的一部分。它的主要功能是提供了一种新的错误处理模式,即As,Is和Unwrap。
运维开发王义杰
2023/08/10
1.3K0
Go错误处理库比较:pkg/errors vs github.com/pkg/errors
Go错误集锦 | 处理error时有哪些常见的陷阱
大家好,我是渔夫子。今天跟大家聊聊在Go中处理error时有哪些常见的陷阱以及如何避免。
Go学堂
2023/01/31
4880
「Go工具箱」一个简单、易用的多错误管理包:go-multierror
大家好,我是渔夫子。本号新推出「Go 工具箱」系列,意在给大家分享使用 go 语言编写的、实用的、好玩的工具。
Go学堂
2023/01/31
5160
Go中这么多创建error的方式,你真的了解它们各自的应用场景吗
由此可知,该接口只有一个返回字符串的Error函数,所有的类型只要实现了该函数,就创建了一个错误类型。
Go学堂
2023/01/31
7280
Go进阶笔记关于Error
其实很多时候是使用的姿势不对,或者说,对于error的用法没有完全理解,这里整理一下关于Go中的error 。
后场技术
2020/12/29
5010
相关推荐
Working with Errors in Go 1.13
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验