聊聊新的Go语言错误处理方案

栏目: Go · 发布时间: 7年前

内容简介:今天早些时候,从目前的情况来看,基本上错误的处理形式基本已经定型,处理方式则是类似于之前的另一个在之前介绍文章中提到过

今天早些时候, golang/x/exp 中默默的更新了一个名曰 xerrors 的包,这个包和同样处于 golang/x/exp 下的另一个名叫 errors 的包名字十分相似,就连介绍也都一致:

 Package errors implements functions to manipulate errors.

This package implements the Go 2 draft designs for error inspection and printing

从目前的情况来看,基本上错误的处理形式基本已经定型,处理方式则是类似于之前的另一个 github.com/pkg/errors 包,但是具体细节不尽相同。

如何处理error?

在之前介绍文章中提到过 github.com/pkg/errors 包的设计思路,那么在 Go 团队的实现中,这种思路也得到了继承。先从一个小例子开始:

package main

import (
	"fmt"

	"golang.org/x/exp/xerrors"
)

func raiseError() error {
	return xerrors.New("a new error")
}

func main() {
	err := xerrors.Errorf("raiseError: %w", raiseError())
	fmt.Println(err)
}

输出结果:

raiseError: a new error

看起来非常类似于之前 github.com/pkg/errors 的显示内容。而其中 xerrors.Errorf 则充当了之前 errors.Wrap 的功能。 其中值得一提的是 %w ,这个用于包装错误,后续验证错误中也会用到其中的值。

同时,这个包中也包含了几个非常有用的辅助函数,分别是:验证错误类型方法 Is 、错误类型转换方法 As 、错误关系链解除方法 Opaque 和提取内层错误方法 Unwrap 。我们可以用一个简单的演示来说明这种关系:

var (
	ErrBase = xerrors.New("a new error")
)

func main() {
	err := xerrors.Errorf("raiseError: %w", ErrBase)
	fmt.Println(ErrBase == ErrBase)                       // 地址相同
	fmt.Println(err == ErrBase)                           // 基于ErrBase包装之后不同
	fmt.Println(xerrors.Is(err, ErrBase))                 // 验证是否为基于ErrBase
	fmt.Println(xerrors.Opaque(err) == err)               // 解除关系链之后不为相同地址
	fmt.Println(xerrors.Is(xerrors.Opaque(err), ErrBase)) // 解除关系链之后无法确定关系
	fmt.Println(xerrors.Unwrap(err) == ErrBase)           // 获取内层错误为原错误,地址相同
}

输出结果为:

true
false
true
false
false
true

即便是在包裹多层之后,错误类型也能通过 Is 方法正确识别:

func main() {
	err := xerrors.Errorf("raiseError: %w", ErrBase)
	err2 := xerrors.Errorf("wrap#01: %w", err)
	err3 := xerrors.Errorf("wrap#02: %w", err2)
	fmt.Println(xerrors.Is(err, ErrBase))
	fmt.Println(xerrors.Is(err3, ErrBase)) // 能够正确识别关系,打印为true
}

如果需要打印详细的调用链路,则可以通过标准库 fmt 相关功能进行输出,比如 Printf 或者 Sprintf 等。

func main() {
	err := xerrors.Errorf("raiseError: %w", ErrBase)
	err2 := xerrors.Errorf("wrap#01: %w", err)
	err3 := xerrors.Errorf("wrap#02: %w", err2)
	fmt.Printf("%+v\n", err3)
}

输出链路如下:

wrap#02:
    main.main
        /.../error.go:16
  - wrap#01:
    main.main
        /.../error.go:15
  - raiseError:
    main.main
        /.../error.go:14
  - a new error:
    main.init
        /.../error.go:10

但是注意,使用 %w 进行包装时,仅能单次包装单个错误,比如下面这种两个错误同时包装时,是会无法识别的:

var (
	ErrBase  = xerrors.New("a new error")
	ErrBase2 = xerrors.New("another new error")
)

func main() {
	err := xerrors.Errorf("raiseError: %w, %w", ErrBase2, ErrBase2)
	fmt.Println(xerrors.Is(err, ErrBase))
	fmt.Println(xerrors.Is(err, ErrBase2))
}

落地使用

在具体项目实现中,如对外提供的库文件中,我建议可以参考其他语言的实现方式,定义一个特殊的基础错误类型 ErrBase ,所有其他错误类型均由此类型派生,则后续外部在使用过程中,只需通过 xerros.Is 判定错误类型,则可以快速判定错误是否来自于本包,并且可以借助此功能统一单独处理来自于此第三方包的异常。

如果你有其他的建议和疑问,也欢迎在留言区中留言讨论。另外,根据实际实现代码来看,其中还有一些边缘情况未考虑或者未做处理,由于是试验性库,本库在使用过程中需自行承担所带来的风险。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Designing with Web Standards (2nd Edition)

Designing with Web Standards (2nd Edition)

Jeffrey Zeldman / Peachpit Press / 2006-07-06 / USD 44.99

Best-selling author, designer, and web standards evangelist Jeffrey Zeldman has updated his classic, industry-shaking guidebook. This new edition--now in full color--covers improvements in best prac......一起来看看 《Designing with Web Standards (2nd Edition)》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具