errors
errors
提供了一系列操作错误的函数,用于创建、检查和操作错误对象。在Go语言中,错误是一种内建的接口类型,定义为:
type error interface {
Error() string
}
1 func New(text string) error
作用:创建简单错误对象
参数:text string
(错误信息文本)
返回值:携带文本的错误对象
注意事项:
不支持嵌套错误(不可用
Unwrap()
解析)相同文本也会创建不同对象(需用
errors.Is()
判断相等性)
package main
import (
"errors"
"fmt"
)
func main() {
// 创建基础错误
err := errors.New("文件读取失败")
fmt.Println(err.Error()) // 输出: 文件读取失败
// 相同文本创建的不同错误对象
err2 := errors.New("文件读取失败")
fmt.Println(err == err2) // false:不同内存地址
fmt.Println(errors.Is(err, err2)) // false:无自定义Is方法,无法识别为相同错误
}
2 func Unwrap(err error) error
作用:解包嵌套错误
参数:err error
(嵌套错误对象)
返回值:
成功:解包后的错误
失败:
nil
注意事项:仅支持实现
Unwrap() error
的错误类型多层嵌套需多次调用
package main
import (
"errors"
"fmt"
)
func main() {
// 创建两层嵌套错误
baseErr := errors.New("原始错误")
wrappedErr := fmt.Errorf("包装层1: %w", fmt.Errorf("包装层2: %w", baseErr))
// 第一次解包
if unwrapped := errors.Unwrap(wrappedErr); unwrapped != nil {
fmt.Println(unwrapped) // 输出: 包装层2: 原始错误
}
// 第二次解包
if unwrapped2 := errors.Unwrap(unwrapped); unwrapped2 != nil {
fmt.Println(unwrapped2) // 输出: 原始错误
}
// 继续解包
if unwrapped3 := errors.Unwrap(unwrapped2); unwrapped3 == nil {
fmt.Println("无法继续解包") // 触发:baseErr未实现Unwrap()
}
}
3 func Is(err, target error) bool
作用:检查错误链中是否存在目标错误 参数:
err error
:错误链起点target error
:目标错误 返回值:true
:错误链中存在目标错误false
:不存在 注意事项:通过递归调用
Unwrap()
遍历错误链支持自定义
Is(error) bool
方法(优先级最高)target
应为可比较的单一错误值
package main
import (
"errors"
"fmt"
)
type TimeoutError struct{}
func (e TimeoutError) Error() string { return "请求超时" }
func main() {
baseErr := TimeoutError{}
wrappedErr := fmt.Errorf("操作失败: %w", baseErr)
// 检查错误链
if errors.Is(wrappedErr, baseErr) {
fmt.Println("检测到TimeoutError") // 输出: 检测到TimeoutError
}
// 检查未实现的自定义错误
customErr := errors.New("自定义错误")
fmt.Println(errors.Is(wrappedErr, customErr)) // false:错误链中不存在
}
4 func As(err error, target any) bool
作用:提取错误链中特定类型的错误 参数:
err error
:错误链起点target any
:目标类型指针(必须非nil
) 返回值:true
:找到匹配类型并赋值给target
false
:未找到 注意事项:target
必须是接口或具体类型的指针错误赋值到
target
时会保留原始错误信息类型不匹配或
target
为nil
时会导致 panic
package main
import (
"errors"
"fmt"
)
type NetworkError struct{ Msg string }
func (e NetworkError) Error() string { return e.Msg }
func main() {
baseErr := NetworkError{Msg: "连接断开"}
wrappedErr := fmt.Errorf("网络故障: %w", baseErr)
var target NetworkError
if errors.As(wrappedErr, &target) {
fmt.Println(target) // 输出: 连接断开
}
// 错误用法:target未初始化指针
var p *NetworkError
defer func() {
if r := recover(); r != nil {
fmt.Println("触发panic:", r) // 输出: target不能为nil指针
}
}()
errors.As(wrappedErr, p) // panic: target为nil指针
}
5 func Join(errs ...error) error
作用:合并多个错误为一个复合错误
参数:errs ...error
(错误列表)
返回值:
非空错误列表:返回
multiError
对象空列表:返回
nil
注意事项:Unwrap()
返回nil
(需用As()
/Is()
处理)遍历错误链时优先匹配第一个可解包错误
复合错误的
Error()
返回所有错误文本拼接
package main
import (
"errors"
"fmt"
)
func main() {
err1 := errors.New("错误1")
err2 := errors.New("错误2")
joinedErr := errors.Join(err1, err2)
fmt.Println(joinedErr) // 输出: 错误1\n错误2
// Unwrap无法解包复合错误
if errors.Unwrap(joinedErr) == nil {
fmt.Println("无法解包Join的错误") // 输出: 无法解包Join的错误
}
// 通过Is检查成员
if errors.Is(joinedErr, err1) {
fmt.Println("找到错误1") // 输出: 找到错误1
}
// 空列表返回nil
emptyErr := errors.Join()
fmt.Println(emptyErr) // nil
}
6 建议
错误比较:
不要用
==
比较errors.New()
的错误(除非是同实例)用
errors.Is()
代替值比较(支持嵌套错误和自定义行为)
嵌套结构:
使用
fmt.Errorf("...%w...", err)
包裹错误避免深层嵌套(超过 5 层降低可读性)
复合错误:
Join()
适合合并无关错误(如批量操作)优先包裹因果错误(
%w
)而非拼接文本(fmt.Errorf
)
自定义错误:
实现
Unwrap() error
支持嵌套实现
Is() bool
或As()
支持高级匹配
最后更新于