go 错误处理强调显式检查与类型安全:优先用 errors.is()/as() 判断哨兵错误或提取具体类型,避免字符串匹配;包装错误必须用 %w 保留链;自定义错误需嵌入 %w;旧版库可能不支持 is/as,应查文档确认。

Go 语言本身不支持异常(try/catch),所有错误都必须显式检查,第三方库也严格遵循这一约定——error 是返回值的一部分,不是被“抛出”的。
第三方库的 error 类型通常实现了 Is() 和 As()
主流库(如 github.com/aws/aws-sdk-go-v2、github.com/jackc/pgx/v5、go.etcd.io/etcd/client/v3)会为关键错误定义具体类型,并实现 errors.Is() 和 errors.As() 支持:
-
errors.Is(err, pgx.ErrNoRows)可安全判断是否为“无行”错误,不依赖字符串匹配 -
var e *pgconn.PgError; if errors.As(err, &e) { ... }能提取底层 PostgreSQL 错误结构,获取Code、Message等字段 - 自定义错误类型一般嵌入
fmt.Errorf("...: %w", underlying)并用%w包装,才能被errors.Is()向下穿透
不要用 err.Error() 做逻辑判断
字符串匹配脆弱且易失效,比如:
动态WEB网站中的PHP和MySQL详细反映实际程序的需求,仔细地探讨外部数据的验证(例如信用卡卡号的格式)、用户登录以及如何使用模板建立网页的标准外观。动态WEB网站中的PHP和MySQL的内容不仅仅是这些。书中还提到如何串联JavaScript与PHP让用户操作时更快、更方便。还有正确处理用户输入错误的方法,让网站看起来更专业。另外还引入大量来自PEAR外挂函数库的强大功能,对常用的、强大的包
// ❌ 危险:版本更新后消息变,或本地化导致内容不同
if strings.Contains(err.Error(), "connection refused") { ... }
// ✅ 正确:用库提供的哨兵错误或类型断言
if errors.Is(err, syscall.ECONNREFUSED) { ... }
if netErr, ok := err.(net.Error); ok && netErr.Timeout() { ... }
- 某些库(如
net/http)导出http.ErrServerClosed这类哨兵错误,直接比较即可 - 若库未导出具体错误类型,可查其源码看是否实现了
Temporary()、Timeout()等方法,再用类型断言调用
包装第三方错误时,避免丢失原始上下文
你自己的函数调用第三方库出错,应使用 %w 包装而非 %s:
立即学习“go语言免费学习笔记(深入)”;
// ❌ 丢失原始 error 链,无法用 errors.Is() 判断底层原因
return fmt.Errorf("failed to fetch user: %s", err)
// ✅ 保留错误链,上层仍能识别 pgx.ErrNoRows 等
return fmt.Errorf("failed to fetch user: %w", err)
- 如果需要添加调试信息(如请求 ID),放在前面,仍用
%w结尾:fmt.Errorf("req=%s: db query failed: %w", reqID, err) - 用
errors.Unwrap()手动展开错误链仅在极少数诊断场景需要,日常处理优先用errors.Is()/errors.As()
最常被忽略的一点:很多第三方库的错误类型只在特定版本才支持 Is()/As(),旧版可能只返回裸 fmt.Errorf。遇到不确定的库,先查它的 errors.go 或文档里有没有导出哨兵变量或公开错误类型——没导出,就别硬断言。









