Go errors.Join 怎样判断其中是否包含指定错误
来源:17golang原创
时间:2026-10-28 22:10:05 175浏览 收藏
用 errors.Is(joined, target) 判断 errors.Join 合并结果是否匹配指定错误。Is会检查错误本身及其包装的子错误,普通的 joined == target 只比较最外层值,不能代替这项检查。目标错误应使用预先定义并复用的哨兵值,不要临时再创建一个同文案的错误。
官方地址:https://pkg.go.dev/errors
先定义一个批量检查小工具
假设一个资料清单检查器要同时检查名称和数量,希望一次展示所有问题。名称缺失与数量无效是两个独立错误类别,调用方既要得到合并错误,也要分别决定怎样提示用户。我们用包级哨兵保存类别,用%w附加字段上下文,再用Join合并。
errors.Join自Go 1.20加入标准库。读者准备支持该接口的Go环境,把后面的完整片段保存为main.go即可。示例只检查内存中的记录,不访问网站、数据库或文件,不需要额外依赖。

保留包装并用Is判断
package main
import (
"errors"
"fmt"
"strings"
)
var (
ErrNameMissing = errors.New("名称缺失")
ErrCountInvalid = errors.New("数量无效")
)
type Record struct {
Name string
Count int
}
func checkRecord(r Record) error {
var issues []error
if strings.TrimSpace(r.Name) == "" {
// 用%w保留错误身份,字段名只提供人类可读上下文。
issues = append(issues, fmt.Errorf("字段name: %w", ErrNameMissing))
}
if r.Count
这里两个字段检查都是示例业务规则,并非通用数据标准。重要的是错误关系:%w留下包装关系,Join保存分支,Is按目标查找。如果把%w换成只输出文本的%v,再把结果当普通文本错误返回,原哨兵身份就不在这条包装关系中了。
怎样运行并判断示例行为
# 在保存main.go的目录执行,让Go编译并运行这个内存检查器。 go run main.go
本文没有在本机执行示例,不附带实测日志。按代码中的输入,名称为空白、数量为0,所以两类判断都应成立。把输入改成非空名称与正数后,issues没有元素,Join返回nil,程序应走“记录通过检查”分支。若只改好一个字段,就只应提示另一类问题。
复现时观察分支是否符合输入,不要把多行错误文案的排版当作分类依据。Join的Error文本会把非nil子错误文案以换行组合,文案适合展示或记录;程序分支应依赖Is,而不是strings.Contains。

接入调用方时保留哪些边界
| 需求 | 适合方式 | 误区 |
|---|---|---|
| 判断某一错误类别 | errors.Is(err, sentinel) | 比较合并根节点与哨兵是否相等 |
| 提取具体类型及字段 | errors.As | 把Is当作取出错误对象的方法 |
| 保留上下文和身份 | 包装时使用%w | 只拼接错误文本后期待身份仍存在 |
| 多个类别同时提示 | 独立的匹配判断 | else if让后面的错误类别被遮住 |
Is表达的是“树中存在匹配”。它不承诺列出所有命中节点,也不证明树中只含这一种错误。自定义错误可以实现Is方法来定义等价匹配,因此“包含指定错误”在这里应按匹配语义理解,不总是同一个对象引用。
Join会丢弃nil输入,全部为nil时返回nil;接口里承载的typed nil却不一定是接口nil,生产者仍要正确表达成功状态。不要靠Join自动修复错误的返回契约。
还有一个常见困惑:errors.Unwrap只处理单错误形式的Unwrap() error,不会替你展开Join的Unwrap() []error。它返回nil不能说明Join没有子错误。多数分类代码直接调用Is或As即可,不必自己写一套递归解析。
同样文案的errors.New为什么匹配不上?
每次New都会创建独立错误值,文案相同不代表身份相同。定义一次哨兵并在产生和判断时复用它,而不是在Is的第二个参数里再New一次。
只有一个非nil输入,可以直接用等号吗?
不要依赖Join只有一个输入时会返回原错误值这一假设。只要语义是判断包装树内是否匹配,就继续使用Is。
发现一种可忽略错误,能把整组错误都忽略吗?
不能只凭一次Is命中就丢弃整个合并结果,里面可能还有其他失败。如果需要逐条处理结果,保留结构化检查结果,或在明确契约下逐个分类,再决定整体状态。
这个小工具可以作为调用方分类的起点:先在产生处保存错误身份,再合并独立问题,最后按业务选择独立提示或明确的优先级。只把Join后的文案传给下游,就会丢失这种可判断能力。
-
502 收藏
-
502 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习