Go跨模块错误处理的核心是统一错误类型、明确来源、避免重复包装并保持可追溯性,关键在于错误在合适位置被识别响应,而非捕获所有错误。
Go 中跨模块错误处理的核心是统一错误类型、明确错误来源、避免重复包装,同时保持调用链的可追溯性。关键不在于“捕获所有错误”,而在于“让错误在合适的位置被识别和响应”。
每个模块应导出自己的错误变量或自定义错误类型,便于外部识别和判断。避免直接返回 errors.New 或 fmt.Errorf 的裸字符串错误。
var ErrNotF
ound = errors.New("item not found") 定义可比较的哨兵错误(sentinel error)Error() 和 Unwrap() 方法fmt.Errorf("failed to parse config: %w", err) 包装底层错误,但只在边界处(如导出函数)做一次错误从底层模块向上透传时,中间层不应无意义地反复包装。只有当需要补充当前层语义(如操作意图、失败阶段)时才用 %w 包装。
fmt.Errorf("get user: %w", err)
errors.Is(err, mymodule.ErrNotFound) 判断哨兵错误,用 errors.As(err, &e) 提取自定义错误详情面向终端用户、日志系统、运维排查的错误信息应有区分。模块导出的错误默认只含技术标识(如错误码、类型),不含敏感或冗余描述。
fmt.Sprintf("%+v", err) 查看完整堆栈(需启用 fmt 的扩展格式)mystore.ErrLocked 转为 “资源正被使用,请稍后重试”fmt.Errorf("in store.Delete: %w", err),但不导出带行号/路径的错误字符串当模块间协议较松(如通过 RPC 或 HTTP 调用),纯类型判断不可靠,可引入轻量级错误码机制。
const CodeNotFound = "NOT_FOUND"
Code string 字段,并提供 Code() string 方法errors.Is 做类型判断基本上就这些。Go 的错误处理不是靠框架兜底,而是靠约定 + 工具 + 习惯——定义清晰、包装克制、判定明确、暴露有度。