Go语言如何使用Go 1.13错误包装_Golang标准库错误处理技巧
发布时间 - 2026-01-31 00:00:00 点击率:次Go 1.13 的 errors.Is 和 errors.As 用于递归判断错误链中的目标错误或类型,需配合 fmt.Errorf("%w") 包装和自定义 Unwrap() 方法;直接 == 或类型断言会失败,%w 必须是 fmt.Errorf 唯一且末尾的动词。
Go 1.13 的 errors.Is 和 errors.As 怎么用才不踩坑
Go 1.13 引入错误包装(error wrapping)后,errors.Is 和 errors.As 成为判断错误类型和提取底层错误的核心工具——但它们**不是简单替代 == 或类型断言**。
常见错误是直接对包装后的错误做 err == io.EOF 或 err.(*os.PathError),结果永远失败。因为包装链中原始错误被嵌套在 fmt.Errorf("...: %w", err) 生成的结构体里。
-
errors.Is(err, io.EOF)会递归检查整个错误链,找到任意一层是io.EOF就返回true -
errors.As(err, &target)会逐层尝试类型断言,成功则把匹配到的错误赋值给target(注意传指针) - 如果错误链里有多个同类型错误,
errors.As只返回最内层(第一个匹配到的) - 不要对非包装错误(如裸
errors.New)滥用errors.As,它仍能工作,但无包装意义
%w 格式动词必须严格配对 fmt.Errorf 才生效
只有 fmt.Errorf 中显式使用 %w(且只支持一个),才会生成可被 errors.Unwrap 解包的包装错误;其他方式(比如拼接字符串、用 %s 插入错误)都会丢失包装能力。
- ✅ 正确:
fmt.Errorf("read failed: %w", io.ErrUnexpectedEOF) - ❌ 错误:
fmt.Errorf("read failed: %s", io.ErrUnexpectedEOF)→ 得到普通字符串错误,无法Is或As - ❌ 错误:
fmt.Errorf("read failed: %w, retry=%d", io.ErrUnexpectedEOF, n)→ 编译报错:格式动词%w必须是最后一个参数 - ⚠️ 注意:
%w后面不能跟其他动词,也不能出现在多参数fmt.Errorf的中间位置
自定义错误类型如何支持包装和解包
如果你写自己的错误类型并希望它能参与 errors.Is/errors.As 流程,必须实现 Unwrap() error 方法。标准库中 *os.PathError、*net.OpError 都已实现。
- 单层包装:返回你持有的底层错误(如字段
Err error) - 多层包装:可以返回
nil(表示无更多包装),或返回另一个实现了Unwrap()的错误 - 不要在
Unwrap()中返回自身或循环引用,否则errors.Is可能无限递归 - 示例:
type MyError struct { Msg string Err error // 底层错误,可能为 nil } func (e *MyError) Error() string { return e.Msg } func (e *MyError) Unwrap() error { return e.Err }
性能与调试时容易忽略的细节
错误包装本身开销极小,但过度包装(比如每层都加日志上下文)会让错误链变长,影响 errors.Is 查找效率,也加大了 fmt.Printf("%+v", err) 的输出体积。
- 调试时用
%+v而不是%v才能看到完整包装链(含文件行号) -
errors.Unwr只解一层;要获取最底层错误,得循环调用直到返回
ap(err)
nil - 日志记录建议用
fmt.Sprintf("%+v", err),而不是err.Error(),否则丢失堆栈和包装信息 - HTTP handler 等入口处捕获错误后,应优先用
errors.Is做语义判断(如是否为os.ErrNotExist),再决定返回 404 还是 500,而非依赖错误字符串匹配
# go
# golang
# go语言
# app
# 工具
# 栈
# ai
# 标准库
# EOF
# Error
# printf
# 字符串
# 结构体
# 递归
# 循环
# 指针
# 堆
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
制作ppt免费网站有哪些,有哪些比较好的ppt模板下载网站?
阿里云网站搭建费用解析:服务器价格与建站成本优化指南
Laravel如何操作JSON类型的数据库字段?(Eloquent示例)
公司门户网站制作公司有哪些,怎样使用wordpress制作一个企业网站?
HTML透明颜色代码怎么让下拉菜单透明_下拉菜单透明背景指南【技巧】
韩国服务器如何优化跨境访问实现高效连接?
制作电商网页,电商供应链怎么做?
详解Oracle修改字段类型方法总结
如何用免费手机建站系统零基础打造专业网站?
如何用ChatGPT准备面试 模拟面试问答与职场话术练习教程
用v-html解决Vue.js渲染中html标签不被解析的问题
魔毅自助建站系统:模板定制与SEO优化一键生成指南
阿里云高弹*务器配置方案|支持分布式架构与多节点部署
INTERNET浏览器怎样恢复关闭标签页_INTERNET浏览器标签恢复快捷键与方法【指南】
jquery插件bootstrapValidator表单验证详解
Laravel怎么配置.env环境变量_Laravel生产环境敏感数据保护与读取【方法】
米侠浏览器网页背景异常怎么办 米侠显示修复
网站制作价目表怎么做,珍爱网婚介费用多少?
夸克浏览器网页跳转延迟怎么办 夸克浏览器跳转优化
HTML5空格和nbsp有啥关系_nbsp的作用及使用场景【说明】
Laravel怎么上传文件_Laravel图片上传及存储配置
浅谈redis在项目中的应用
Laravel怎么实现微信登录_Laravel Socialite第三方登录集成
Laravel如何生成PDF或Excel文件_Laravel文档导出工具与使用教程
如何快速搭建虚拟主机网站?新手必看指南
悟空浏览器如何设置小说背景色_悟空浏览器背景色设置【方法】
如何在 Python 中将列表项按字母顺序编号(a.、b.、c. …)
如何在阿里云服务器自主搭建网站?
iOS UIView常见属性方法小结
JS去除重复并统计数量的实现方法
Edge浏览器如何截图和滚动截图_微软Edge网页捕获功能使用教程【技巧】
如何在腾讯云免费申请建站?
如何在万网ECS上快速搭建专属网站?
悟空识字怎么关闭自动续费_悟空识字取消会员自动扣费步骤
实例解析angularjs的filter过滤器
如何基于云服务器快速搭建个人网站?
儿童网站界面设计图片,中国少年儿童教育网站-怎么去注册?
Laravel模型关联查询教程_Laravel Eloquent一对多关联写法
如何制作一个表白网站视频,关于勇敢表白的小标题?
如何用搬瓦工VPS快速搭建个人网站?
Laravel观察者模式如何使用_Laravel Model Observer配置
打开php文件提示内存不足_怎么调整php内存限制【解决方案】
Laravel如何自定义分页视图?(Pagination示例)
东莞专业网站制作公司有哪些,东莞招聘网站哪个好?
b2c电商网站制作流程,b2c水平综合的电商平台?
如何在万网利用已有域名快速建站?
Laravel如何实现全文搜索功能?(Scout和Algolia示例)
Laravel Eloquent性能优化技巧_Laravel N+1查询问题解决
如何在云指建站中生成FTP站点?
python中快速进行多个字符替换的方法小结


