golang标准库errors替代方案与错误处理增强插件库errors的使用
Golang标准库errors替代方案与错误处理增强插件库errors的使用
Emperror/errors是一个功能强大的Golang错误处理库,它结合了标准库errors和github.com/pkg/errors的特性,并添加了许多增强功能。
主要特性
标准库特性
New
创建带有堆栈跟踪的错误Unwrap
支持Go 1.13包装器接口和pkg/errors的causer接口- 向后兼容的
Is
和As
函数
github.com/pkg/errors特性
New
,Errorf
,WithMessage
,WithMessagef
,WithStack
,Wrap
,Wrapf
函数行为与原库相同Cause
支持两种错误解包接口
额外特性
NewPlain
创建无上下文(如堆栈跟踪)的错误Sentinel
创建常量错误的简写类型WithStackDepth
允许自定义调用深度附加堆栈跟踪- 条件性附加堆栈跟踪的函数
- 多错误聚合
- 添加键值对到错误的函数
match
包用于错误匹配
安装
go get emperror.dev/errors
使用示例
基本用法
package main
import "emperror.dev/errors"
// ErrSomethingWentWrong 是一个哨兵错误,适用于单个API层
const ErrSomethingWentWrong = errors.Sentinel("something went wrong")
// ErrMyError 是可以从公共API返回的错误
type ErrMyError struct {
Msg string
}
func (e ErrMyError) Error() string {
return e.Msg
}
func foo() error {
// 为哨兵错误附加堆栈跟踪
return errors.WithStack(ErrSomethingWentWrong)
}
func bar() error {
return errors.Wrap(ErrMyError{"something went wrong"}, "error")
}
func main() {
if err := foo(); err != nil {
if errors.Cause(err) == ErrSomethingWentWrong { // 或者使用 errors.Is(ErrSomethingWentWrong)
// 处理错误
}
}
if err := bar(); err != nil {
if errors.As(err, &ErrMyError{}) {
// 处理错误
}
}
}
错误匹配
package main
import (
"emperror.dev/errors"
"emperror.dev/errors/match"
)
// ErrSomethingWentWrong 是一个哨兵错误
const ErrSomethingWentWrong = errors.Sentinel("something went wrong")
type clientError interface{
ClientError() bool
}
func foo() error {
// 为哨兵错误附加堆栈跟踪
return errors.WithStack(ErrSomethingWentWrong)
}
func main() {
var ce clientError
matcher := match.Any{match.As(&ce), match.Is(ErrSomethingWentWrong)}
if err := foo(); err != nil {
if matcher.MatchError(err) {
// 可以使用匹配器编写复杂的错误处理条件
}
}
}
开发
欢迎贡献代码!
- 克隆仓库
- 在新分支上修改
- 运行测试套件:
./pleasew build
./pleasew test
./pleasew gotest
./pleasew lint
- 提交、推送并创建PR
许可证
MIT许可证。详细信息请查看许可证文件。
部分代码受第三方库启发(或完全复制),它们的许可证可以在第三方许可证文件中找到。
更多关于golang标准库errors替代方案与错误处理增强插件库errors的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang标准库errors替代方案与错误处理增强插件库errors的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang 错误处理增强方案与替代库
在 Go 语言中,标准库的 errors
包提供了基本的错误处理功能,但随着项目复杂度增加,开发者往往需要更强大的错误处理能力。以下是几种流行的替代方案和增强插件库。
1. pkg/errors 库
pkg/errors
是最流行的 errors 替代库之一,提供了错误堆栈跟踪和错误包装功能。
import (
"github.com/pkg/errors"
"fmt"
)
func main() {
err := process()
if err != nil {
fmt.Printf("%+v\n", err) // 打印完整堆栈
}
}
func process() error {
err := readFile()
if err != nil {
return errors.Wrap(err, "process failed") // 包装错误并添加上下文
}
return nil
}
func readFile() error {
return errors.New("file not found") // 创建新错误
}
主要特性:
Wrap()
包装错误并添加上下文信息WithStack()
添加调用堆栈Cause()
获取原始错误%+v
格式化打印完整堆栈信息
2. hashicorp/go-multierror
当需要处理多个错误时,go-multierror
非常有用。
import (
"github.com/hashicorp/go-multierror"
"errors"
)
func main() {
var result error
// 模拟多个操作,每个都可能失败
for i := 0; i < 3; i++ {
if err := doTask(i); err != nil {
result = multierror.Append(result, err)
}
}
if result != nil {
fmt.Println(result) // 打印所有错误
}
}
func doTask(i int) error {
return errors.New(fmt.Sprintf("task %d failed", i))
}
3. uber-go/multierr
Uber 的 multierr 是另一个处理多个错误的库,API 更现代化。
import (
"go.uber.org/multierr"
"errors"
)
func main() {
var err error
err = multierr.Append(err, errors.New("first error"))
err = multierr.Append(err, errors.New("second error"))
fmt.Println(err) // "first error; second error"
}
4. golang.org/x/xerrors
Go 官方实验性的增强错误包,提供了类似 pkg/errors 的功能。
import (
"golang.org/x/xerrors"
"fmt"
)
func main() {
err := process()
if err != nil {
fmt.Printf("%+v\n", err)
}
}
func process() error {
err := readFile()
if err != nil {
return xerrors.Errorf("process failed: %w", err)
}
return nil
}
func readFile() error {
return xerrors.New("file not found")
}
5. 自定义错误类型
对于更复杂的场景,可以定义自己的错误类型:
type BusinessError struct {
Code int
Message string
Cause error
}
func (e *BusinessError) Error() string {
if e.Cause != nil {
return fmt.Sprintf("%s (code: %d): %v", e.Message, e.Code, e.Cause)
}
return fmt.Sprintf("%s (code: %d)", e.Message, e.Code)
}
func main() {
err := &BusinessError{
Code: 404,
Message: "Resource not found",
Cause: errors.New("file missing"),
}
fmt.Println(err)
}
最佳实践建议
- 错误包装:使用
Wrap
或WithStack
为错误添加上下文 - 错误检查:使用
errors.Is
和errors.As
(Go 1.13+) 进行错误类型检查 - 错误日志:记录完整堆栈信息便于调试
- 错误处理:在应用边界处理错误,不要在中间层忽略错误
- 错误分类:区分业务错误和系统错误
// Go 1.13+ 错误检查示例
if errors.Is(err, os.ErrNotExist) {
// 处理文件不存在的错误
}
var pathError *os.PathError
if errors.As(err, &pathError) {
// 处理 PathError 类型错误
}
选择哪种方案取决于项目需求:简单的项目可以使用标准库或 xerrors,需要堆栈跟踪的选择 pkg/errors,需要合并多个错误的选择 multierror 或 uber/multierr。