推荐用 const 声明字符串错误码(如 ErrUserNotFound = "user_not_found"),配合同名 CodeError 变量和单行注释,实现 IDE 跳转、grep 匹配与文档自动提取;禁用 iota int 码,因其无法语义搜索且易冲突。

Go 错误码怎么结构化才方便搜索
错误码必须能被 IDE 跳转、被 grep 匹配、被文档工具识别,硬编码字符串或分散在 errors.New 里就等于放弃可维护性。核心是把错误码和描述绑定在唯一、可导出的变量上。
推荐用 const + 自定义 error 类型组合:
- 所有错误码用
const声明,前缀统一(如ErrUserNotFound),值为字符串字面量(如"user_not_found"),不拼接、不运行时生成 - 定义一个
CodeError结构体,字段包含Code(string)、Message(string)、HTTPStatus(int)等,实现Error()方法 - 每个业务错误都用该结构体实例化,且变量名与 const 名一致(如
var ErrUserNotFound = &CodeError{Code: UserNotFound, Message: "用户不存在"})
这样既支持 errors.Is(err, ErrUserNotFound),又能让 grep -r "user_not_found" 一次性定位所有使用点。
如何从 Go 代码自动提取错误码生成文档
靠手写文档一定会过期。关键不是“能不能生成”,而是“生成器能不能稳定识别你定义的模式”。别用通用 AST 工具扫全项目,聚焦在你实际声明错误的那几个文件上。
立即学习“go语言免费学习笔记(深入)”;
实操建议:
- 只扫描指定路径下的
*_error.go文件(如pkg/error/xxx_error.go),避免误入 test 或 vendor - 正则匹配 const 行:用
^const\s+(Err\w+)\s+=\s+"([^"]+)"提取变量名和错误码字符串 - 紧随其后的
var\s+\1\s+=行(即同名变量)用来提取注释,用//\s+(.+)捕获单行注释作为描述 - 输出为 Markdown 表格时,列顺序固定为:
Code、Variable、Description、HTTP Status(若结构体字段存在)
示例片段:
const ErrUserNotFound = "user_not_found"
// 用户不存在,请求的用户 ID 在数据库中未找到
var ErrUserNotFound = &CodeError{Code: ErrUserNotFound, Message: "用户不存在", HTTPStatus: 404}为什么不能用 iota + int 错误码做搜索
int 类型错误码看着紧凑,但实际破坏搜索链路:IDE 找不到引用、grep 匹配不到语义、HTTP 日志里只留数字无法直觉判断含义。
更麻烦的是隐式转换风险:
- 函数返回
int错误码,调用方容易直接和字面量比较(if err == 404),绕过类型检查 - 不同模块用相同
iota起始值,导致码值冲突,运行时才发现 - 文档生成器无法把
404和ErrUserNotFound关联起来,除非额外维护映射表——这又回到手动同步的老路
字符串码天然带语义,"user_not_found" 比 1001 更容易被搜索、被理解、被翻译。
文档生成脚本跑不起来?先检查这三个点
常见失败不是语法错,而是路径和上下文没对齐。
-
go run脚本时,当前工作目录是否在 module 根下?否则os.ReadDir("pkg/error")会报no such file - 正则是否忽略大小写或空格?Go 源码里
const后可能有多个空格或 tab,建议用\s+而非固定空格 - 注释是否跨行?目前方案只处理紧邻 const 下方的单行
//注释,不支持/* */或空行隔开的注释——如果用了,就得改解析逻辑,但多数团队没必要为这个加复杂度
真正难的不是生成文档,是让所有人遵守同一套错误声明规范。只要第一版跑通,后续靠 CI 检查新错误是否符合 const + var + 注释三件套,就能卡住退化。










