如何使用Golang错误包装与解包_使用errors.Unwrap获取原始错误
发布时间 - 2026-01-02 00:00:00 点击率:次Go 1.13 引入错误包装与解包机制,通过 fmt.Errorf 的 %w 动词嵌套错误形成链式结构,配合 errors.Unwrap(单层解包)、errors.Is/As(自动遍历链式匹配或类型提取)实现清晰可追溯的错误处理。
Go 1.13 引入了错误包装(error wrapping)和解包(unwrapping)机制,让错误处理更清晰、可追溯。核心在于用 fmt.Errorf 配合 %w 动词包装错误,并用 errors.Unwrap 或 errors.Is/errors.As 向下查找原始错误。
用 %w 包装错误,保留原始上下文
包装错误不是简单拼接字符串,而是将底层错误“嵌套”进去,形成链式结构:
说明: %w 会把传入的 error 值作为内部错误保存,调用 Unwrap() 方法即可获取它。
建议:
- 只在需要添加上下文(如函数名、参数、阶段标识)时包装,避免无意义层层包裹
- 不要对
nil错误使用%w,否则fmt.Errorf("xxx: %w", nil)会返回nil错误 - 示例:
func readFile(path string) error {
data, err := os.ReadFile(path)
if err != nil {
return fmt.Errorf("read file %q failed: %w", path, err) // 包装
}
// ...
return nil
}
用 errors.Unwrap 获取直接被包装的错误
errors.Unwrap 返回错误的直接下一层(即被 %w 包裹的那个),如果该错误不支持 Unwrap() error 方法或返回 nil,则结果为 nil。
说明: 它只解一层,不是递归解包。适合做单步检查或手动遍历错误链。
建议:
- 不要依赖多次调用
Unwrap手动“剥洋葱”,应优先用errors.Is或errors.As - 可配合循环实现自定义解包(但一般不需要):
for err != nil {
if os.IsNotExist(err) {
return fmt.Errorf("file missing: %w", err)
}
err = errors.Unwrap(err) // 仅解一层
}
推荐方式:用 errors.Is 和 errors.As 判断和提取原始错误
比起手动 Unwrap,errors.Is 会自动沿整个错误链向上匹配目标错误(比如 os.ErrNotExist),errors.As 则用于提取特定类型的错误值。
说明: 它们内部已处理多层包装,语义清晰、安全可靠。
建议:
- 判断是否是某类错误(如超时、不存在、权限拒绝)→ 用
errors.Is(err, target) - 需要访问错误的具体字段或方法(如
*os.PathError的Path字段)→ 用errors.As(err, &target) - 示例:
if errors.Is(err, os.ErrNotExist) {
log.Println("file does not exist")
}
var pathErr *os.PathError
if errors.As(err, &pathErr) {
log.Printf("failed on path: %s", pathErr.Path)
}
注意:自定义错误类型需实现 Unwrap 方法才能被正确解包
如果你定义了自己的错误类型并希望它能参与标准解包流程,必须显式实现 Unwrap() error 方法。
说明: 只有实现了该方法的错误,才会被 errors.Unwrap、Is、As 等识别为可包装错误。
建议:
- 若错误包含一个底层 error 字段,直接返回它即可
- 若不包装其他错误,返回
nil - 示例:
type MyError struct {
msg string
cause error
}
func (e *MyError) Error() string { retu
rn e.msg }
func (e *MyError) Unwrap() error { return e.cause } // 关键:支持解包
# go
# golang
# app
# ai
# Error
# 字符串
# 递归
# 循环
# nil
# 链式
# 遍历
# 自定义
# 自己的
# 可追溯
# 如果你
# 不需要
# 才会
# 不存在
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
laravel怎么实现图片的压缩和裁剪_laravel图片压缩与裁剪方法
Laravel怎么调用外部API_Laravel Http Client客户端使用
重庆市网站制作公司,重庆招聘网站哪个好?
免费的流程图制作网站有哪些,2025年教师初级职称申报网上流程?
Thinkphp 中 distinct 的用法解析
Laravel用户密码怎么加密_Laravel Hash门面使用教程
制作无缝贴图网站有哪些,3dmax无缝贴图怎么调?
如何快速搭建安全的FTP站点?
JavaScript实现Fly Bird小游戏
大连网站制作公司哪家好一点,大连买房网站哪个好?
Laravel如何使用Laravel Vite编译前端_Laravel10以上版本前端静态资源管理【教程】
网站广告牌制作方法,街上的广告牌,横幅,用PS还是其他软件做的?
新三国志曹操传主线渭水交兵攻略
如何做网站制作流程,*游戏网站怎么搭建?
如何获取上海专业网站定制建站电话?
uc浏览器二维码扫描入口_uc浏览器扫码功能使用地址
北京网站制作费用多少,建立一个公司网站的费用.有哪些部分,分别要多少钱?
javascript中的数组方法有哪些_如何利用数组方法简化数据处理
Laravel如何使用.env文件管理环境变量?(最佳实践)
详解CentOS6.5 安装 MySQL5.1.71的方法
Laravel项目结构怎么组织_大型Laravel应用的最佳目录结构实践
进行网站优化必须要坚持的四大原则
Laravel怎么配置不同环境的数据库_Laravel本地测试与生产环境动态切换【方法】
android nfc常用标签读取总结
Laravel事件监听器怎么写_Laravel Event和Listener使用教程
Laravel如何实现API版本控制_Laravel版本化API设计方案
Win10如何卸载预装Edge扩展_Win10卸载Edge扩展教程【方法】
Laravel Telescope怎么调试_使用Laravel Telescope进行应用监控与调试
HTML透明颜色代码在Angular里怎么设置_Angular透明颜色使用指南【详解】
Laravel storage目录权限问题_Laravel文件写入权限设置
如何在阿里云通过域名搭建网站?
Laravel项目如何进行性能优化_Laravel应用性能分析与优化技巧大全
如何基于云服务器快速搭建网站及云盘系统?
Laravel Eloquent访问器与修改器是什么_Laravel Accessors & Mutators数据处理技巧
Laravel如何实现密码重置功能_Laravel密码找回与重置流程
香港服务器部署网站为何提示未备案?
Laravel如何处理异常和错误?(Handler示例)
制作网站软件推荐手机版,如何制作属于自己的手机网站app应用?
如何用wdcp快速搭建高效网站?
Mybatis 中的insertOrUpdate操作
Laravel如何使用集合(Collections)进行数据处理_Laravel Collection常用方法与技巧
浅述节点的创建及常见功能的实现
微博html5版本怎么弄发语音微博_语音录制入口及时长限制操作【教程】
javascript中数组(Array)对象和字符串(String)对象的常用方法总结
在线制作视频网站免费,都有哪些好的动漫网站?
Laravel怎么实现API接口鉴权_Laravel Sanctum令牌生成与请求验证【教程】
如何在HTML表单中获取用户输入并结合JavaScript动态控制复利计算循环
Laravel如何实现登录错误次数限制_Laravel自带LoginThrottles限流配置【方法】
网站建设保证美观性,需要考虑的几点问题!
使用豆包 AI 辅助进行简单网页 HTML 结构设计


rn e.msg }
func (e *MyError) Unwrap() error { return e.cause } // 关键:支持解包