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.Is 和 errors.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.Is 和 errors.As 方法了:
err := fmt.Errorf("access denied: %w”, ErrPermission)
...
if errors.Is(err, ErrPermission) ...
对于是否包装错误以及如何包装错误并没有统一的答案。
- 看到他我一下子就悟了-- 泛型(2)
- ExtJS4中设置tabpanel的tab高度问题
- Oracle写错误与文件离线
- 看到他我一下子就悟了-- 泛型(1)
- EXTJS4 Grid Filter 插件的使用 与后台数据解析------Extjs 查询筛选功能的实现
- [Java]读取文件方法大全
- WPF Application 类介绍以及怎样修改启动方式
- C#基础知识回顾-- 反射(4)
- C#基础知识回顾-- 反射(3)
- 微信图文消息添加音乐一招搞定 只需修改背景音乐地址
- C#基础知识回顾-- 反射(2)
- MongoDB 主从配置
- Java 处理 Json 实例
- C#基础知识回顾-- 反射(1)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- PHP之多条件混合筛选功能的实现方法
- PHP多进程简单实例小结
- 解决laravel5中auth用户登录其他页面获取不到登录信息的问题
- Yii框架学习笔记之应用组件操作示例
- laravel 之 Eloquent 模型修改器和序列化示例
- TP5框架请求响应参数实例分析
- laravel 模型查询按照whereIn排序的示例
- 解决在laravel中auth建立时候遇到的问题
- php array 转json及java 转换 json数据格式操作示例
- Thinkphp5 如何隐藏入口文件index.php(URL重写)
- 在Laravel中使用GuzzleHttp调用第三方服务的API接口代码
- thinkphp5使html5实现动态跳转的例子
- php 自定义函数实现将数据 以excel 表格形式导出示例
- 解决tp5在nginx下修改配置访问的问题
- 在PHP中实现使用Guzzle执行POST和GET请求