revive 是目前最灵活的常量命名检查方案,支持按导出性分别配置 PascalCase 和 camelCase 规则,并可通过正则精确限定常量命名格式,需在 .golangci.yml 中启用并确保其执行顺序在 goimports/gofumpt 之后。

golangci-lint 默认不检查常量命名,得靠 goconst 和 gofumpt 配合
golangci-lint 本身不内置常量命名风格校验(比如是否全大写、是否带 const 前缀等),它依赖的 linter 插件里,goconst 能发现重复字面量并建议提取为常量,但不判命名;真正管“命名是否符合 Go 习惯”的是 gofumpt(格式化)和 revive(可配置规则)。Go 官方约定:导出常量首字母大写、全大写(如 MaxRetries 或 DEFAULT_TIMEOUT),未导出常量小写驼峰或全小写(如 defaultTimeout)。但这个约定不会被默认启用。
-
gofumpt -extra会强制把导出常量转成 PascalCase(如ErrNotFound),但它不处理全大写下划线风格(ERR_NOT_FOUND)——这种风格在 Go 社区其实不推荐,除非是明确模拟 C 风格枚举 -
revive支持自定义命名规则,需在.revive.toml中启用exported规则,并设置rule = "PascalCase";对未导出常量可用unexported规则约束为camelCase - 别指望
staticcheck或gosimple管命名——它们专注逻辑缺陷,不是风格检查器
怎么用 revive 检查常量命名是否符合 Go 习惯?
revive 是目前最灵活的命名检查方案,支持细粒度控制导出/未导出标识符。它不会自动修复,但能精准报错,适合接入 CI。
- 安装:
go install github.com/mgechev/revive@latest - 在
.golangci.yml中启用 revive 并指定配置文件:linters-settings: revive: config: .revive.toml -
.revive.toml示例(只针对常量):[rule.exported] arguments = ["PascalCase"] severity = "warning" [rule.unexported] arguments = ["camelCase"] severity = "warning"
注意:这会同时作用于 const、var、func、type,如只想限常量,得配合scope或改用正则过滤(见下条) - 更精确的做法:用
rule.regex单独约束常量命名,例如要求导出常量必须匹配^[A-Z][a-zA-Z0-9]*$(PascalCase),未导出常量匹配^[a-z][a-zA-Z0-9]*$
为什么 golint 已弃用,而 revive 成了主流替代?
golint 在 2021 年被官方归档,原因很直接:它把“建议”当“错误”,规则硬编码、无法关闭单条规则、不支持配置、且部分规则(如“注释必须以函数名开头”)已被证明不实用。而 revive 设计就是为替代它:每条规则可开关、可调参数、可设作用域(如只对 const 生效)、支持正则匹配、错误级别可设为 error/warning/info。
-
golint会把const defaultPort = 8080当作违规(未导出却用小写),但它不区分上下文——这个常量本就不该导出,小写完全合理 -
revive的unexported规则默认只检查首字母小写,允许defaultPort、maxRetries,拒绝DefaultPort(未导出却大写) - 如果你项目用了
ALL_CAPS风格常量(比如对接 C 库),revive可通过正则白名单放过:^([A-Z_0-9]+)$,golint则做不到
CI 中跑 golangci-lint 时,常量命名检查容易漏掉什么?
最容易忽略的是作用域混淆和规则优先级。golangci-lint 启动时按 linter 列表顺序加载,如果 revive 排在 goimports 后面,而 goimports 自动加了导出前缀(如把 timeout 改成 Timeout),revive 就可能误报“未导出常量用了大写”。另外,const 块内若混用导出与未导出常量,revive 默认按声明位置判断导出性,但 Go 的导出性只看首字母,跟块无关——这点容易误配规则。
- 确保
revive在.golangci.yml的linters列表中排在goimports、gofumpt之后,避免格式化干扰命名判断 - 不要在
const块里混写导出和未导出常量(如const ( Timeout = 30; defaultTimeout = 10 )),拆成两个块更清晰,也利于 revive 准确识别作用域 - 本地开发时用
golangci-lint run --fast会跳过 revive(因它较慢),CI 必须去掉--fast,否则命名检查形同虚设
实际项目里,常量命名问题往往不是语法错误,而是协作信号弱——别人一眼看不出这个常量能不能跨包用、是不是魔法数字的抽象。把 revive 的命名规则跑稳,比纠结“该用 MAX_RETRY 还是 MaxRetry”更重要。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











