必须用golangci-lint并配好.golangci.yml:因golint已归档禁用,govet默认漏检unmarshal等高危项,staticcheck单独运行易报错;而golangci-lint并行调度多linter,统一配置、超时与输出,ci中一条命令即覆盖全维度检查。

直接装 golangci-lint 并配好 .golangci.yml,别碰 golint、别手动跑 go vet 或 staticcheck 单独命令——这是当前 Go 项目静态分析唯一靠谱的起点。
为什么 golangci-lint run 没报你预期的问题
不是代码没问题,是默认只启用约 10 个基础 linter(比如 govet、errcheck),真正有用的检查根本没开:
-
staticcheck默认关闭:它才报SA1019(弃用 API)、SA1021(空循环)、nil解引用风险,必须在.golangci.yml的linters.enable里显式加进去 -
unused默认关闭:不启用就发现不了未使用的变量、函数、import,哪怕写了var _ = fmt.Println也不会警告 -
goconst默认关闭:重复的 HTTP 状态码字符串、错误文案、SQL 模板不会被识别,对业务逻辑密集型项目尤其关键 -
--enable-all不推荐:会拉起 50+ linter,其中不少已废弃或对中文注释/泛型误报严重(如旧版lll)
.golangci.yml 放哪、怎么写才不被忽略
文件名、位置、缩进,三者错一个就等于没配:
- 文件名必须是
.golangci.yml(不是.golangci.yaml,也不是golangci.yml),大小写敏感 - 必须放在
go.mod所在目录(即 module 根),不是 Git 仓库根;monorepo 里每个子 module 都得有自己的一份 - 缩进只能用空格,不能用 Tab;
linters-settings和run是顶层字段,和linters并列,不是它的子项 - IDE(如 GoLand / VS Code)可能缓存旧配置,改完后要重启或手动触发 “Reload golangci-lint config”
govet 不报 unmarshal 错误?配置根本没生效
写了 json.Unmarshal(b, &v) 却没警告?说明 govet 的 unmarshal 子检查被关了。默认白名单只含 printf、shadow 等几个,不包括 atomic、bools、unmarshal:
- 查
.golangci.yml里有没有linters-settings.govet段;没有就等于用默认白名单 - 加
checks: ["all"](Go 1.21+ 支持),或明确列出:checks: ["printf", "shadow", "unmarshal", "atomic", "bools"] - 删掉
golint:它已归档禁用,任何残留配置(如linters.enable里还开着golint)都会导致误报或失败 - 别手动跑
go vet -unmarshal ./...:golangci-lint内置调用,只需在配置里显式启用子检查项
CI 里失败但本地正常?先查这三处硬性差异
环境不一致比代码问题更常卡住流水线:
-
GO111MODULE:CI 默认可能为off,导致go list -deps解析失败,报package xxx is not in GOROOT——统一设为on - Go 版本差异:
staticcheck在 Go 1.21+ 对泛型支持稳定,旧版本可能 panic 或漏报;CI 脚本里固定 Go 版本(如actions/setup-go@v6指定1.21.10) -
golangci-lint版本漂移:别用latest,CI 安装命令必须带具体版本号,例如:curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $GITHUB_WORKSPACE/ v1.55.2
最易被忽略的是:golangci-lint v1.50+ 强制要求项目根目录存在 go.mod,否则静默跳过子模块或直接报 no go files to analyze;多 module 仓库中,每个子 module 的配置必须独立生效,不能靠“继承”。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











