Golang使用errors.Is判断错误的正确方式

发布时间 - 2026-01-12 00:00:00    点击率:
errors.Is常返回false,因其仅检查错误链中是否存在同一底层错误值或指针,不支持字符串匹配;须用%w包裹、预定义变量或自定义Unwrap方法才能正确识别。

errors.Is 为什么经常返回 false?

因为 errors.Is 只检查错误链中是否存在某个**底层错误值(value)或其指针**,不支持字符串匹配、模糊比较或自定义逻辑。如果你用 errors.New("timeout") 创建的错误和另一个同内容的 errors.New("timeout") 比较,errors.Is 一定返回 false —— 它们是两个不同地址的指针。

必须用 errors.New 或 fmt.Errorf 包装原始错误才能用 errors.Is

只有当错误被显式地用 fmt.Errorf("...: %w", err)errors.Join 等方式包裹(即包含 %w 动词),它才进入错误链;否则 errors.Is 查不到。

  • ✅ 正确:用 %w 包裹底层错误
  • ❌ 错误:只用 %s 或拼接字符串,如 fmt.Errorf("failed: %s", err.Error())
  • ⚠️ 注意:errors.Unwrap 只能解一层,而 errors.Is 会自动遍历整个链(包括嵌套的 %w
err := io.EOF
wrapped := fmt.Errorf("read failed: %w", err)
fmt.Println(errors.Is(wrapped, io.EOF)) // true

自定义错误类型要实现 Unwrap 方法

如果自己定义了错误结构体(比如 type MyError struct{ Msg string; Code int }),默认 errors.Is 查不到它是否等于某个值,除非你显式实现 Unwrap() error 并返回底层错误。

  • 若该错误本身是终端错误(无底层),Unwrap 应返回 nil
  • 若它封装了另一个错误(如调用了 io.ReadFull),就返回那个错误
  • 不要在 Unwrap 中返回新构造的 errors.New —— 地址不同,errors.Is 仍失败
type MyError struct {
    Err error
}

func (e *MyError) Error() string { return "my error" }
func (e *MyError) Unwrap() error { return e.Err } // ✅ 这样 errors.Is 才能穿透

判断标准错误时,优先用预定义变量而非 errors.New

Go 标准库导出的错误(如 io.EOFos.ErrNotExist)是包级变量,地址唯一。直接拿它们做 errors.Is(err, io.EOF) 是安全且推荐的;但千万别写成 errors.Is(err, errors.New("EOF"))

立即学习“go语言免费学习笔记(深入)”;

  • errors.Is(err, io.EOF)
  • errors.Is(err, os.ErrNotExist)
  • errors.Is(err, errors.New("file does not exist"))
  • ⚠️ 第三方库若没暴露错误变量,应查文档看它是否实现了 Unwrap 或提供了 IsXXX() 辅助函数
实际项目中最容易漏掉的是:在中间层日志或转换错误时,下意识用了字符串拼接丢掉了 %w,导致上游再也无法用 errors.Is 判断原始错误类型。这个断点一旦出现,调试时就会发现“明明报了 EOF,却进不了 EOF 分支”。


# go  # golang  # app  # ai  # 标准库  # 为什么  # EOF  # String  # 封装  # Error  # 字符串  # 结构体  # int  # 指针  # Struct  # nil  # 自定义  # 不支持  # 的是  # 链中  # 中间层  # 遍历  # 它是  # 用了  # 时就  # 千万别 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 清除minerd进程的简单方法  Laravel如何配置.env文件管理环境变量_Laravel环境变量使用与安全管理  专业型网站制作公司有哪些,我设计专业的,谁给推荐几个设计师兼职类的网站?  Python自动化办公教程_ExcelWordPDF批量处理案例  Laravel路由Route怎么设置_Laravel基础路由定义与参数传递规则【详解】  网页设计与网站制作内容,怎样注册网站?  油猴 教程,油猴搜脚本为什么会网页无法显示?  Laravel Session怎么存储_Laravel Session驱动配置详解  Laravel如何实现RSS订阅源功能_Laravel动态生成网站XML格式订阅内容【教程】  如何在浏览器中启用Flash_2025年继续使用Flash Player的方法【过时】  Laravel队列由Redis驱动怎么配置_Laravel Redis队列使用教程  Android自定义listview布局实现上拉加载下拉刷新功能  Swift中循环语句中的转移语句 break 和 continue  标题:Vue + Vuex 项目中正确使用 JWT 进行身份认证的实践指南  Win11怎么查看显卡温度 Win11任务管理器查看GPU温度【技巧】  英语简历制作免费网站推荐,如何将简历翻译成英文?  Laravel如何编写单元测试和功能测试?(PHPUnit示例)  javascript如何操作浏览器历史记录_怎样实现无刷新导航  如何选择PHP开源工具快速搭建网站?  IOS倒计时设置UIButton标题title的抖动问题  如何在Windows服务器上快速搭建网站?  如何在Windows 2008云服务器安全搭建网站?  高端企业智能建站程序:SEO优化与响应式模板定制开发  Swift中switch语句区间和元组模式匹配  如何基于云服务器快速搭建个人网站?  Laravel用户密码怎么加密_Laravel Hash门面使用教程  Windows家庭版如何开启组策略(gpedit.msc)?(安装方法)  如何在七牛云存储上搭建网站并设置自定义域名?  php485函数参数是什么意思_php485各参数详细说明【介绍】  如何用5美元大硬盘VPS安全高效搭建个人网站?  如何在Ubuntu系统下快速搭建WordPress个人网站?  Java Adapter 适配器模式(类适配器,对象适配器)优缺点对比  合肥制作网站的公司有哪些,合肥聚美网络科技有限公司介绍?  Android 常见的图片加载框架详细介绍  北京网站制作费用多少,建立一个公司网站的费用.有哪些部分,分别要多少钱?  如何自定义建站之星模板颜色并下载新样式?  HTML5打空格有哪些误区_新手常犯的空格使用错误【技巧】  Claude怎样写结构化提示词_Claude结构化提示词写法【教程】  如何实现建站之星域名转发设置?  Android滚轮选择时间控件使用详解  PHP怎么接收前端传的文件路径_处理文件路径参数接收方法【汇总】  学生网站制作软件,一个12岁的学生写小说,应该去什么样的网站?  中国移动官方网站首页入口 中国移动官网网页登录  Laravel如何保护应用免受CSRF攻击?(原理和示例)  做企业网站制作流程,企业网站制作基本流程有哪些?  Laravel怎么做数据加密_Laravel内置Crypt门面的加密与解密功能  如何快速生成ASP一键建站模板并优化安全性?  海南网站制作公司有哪些,海口网是哪家的?  CSS3怎么给轮播图加过渡动画_transition加transform实现【技巧】  如何在景安云服务器上绑定域名并配置虚拟主机?