golangci-lint是go项目静态检查的事实标准,必须使用而非单独配置go vet或staticcheck;它聚合多linter、统一配置与执行,但需在go.mod同级目录配置.golangci.yml并启用govet全量检查、staticcheck和errcheck等核心规则,否则大量隐患将漏检。

直接用 golangci-lint,别配单独的 go vet 或 staticcheck。它不是“可选项”,而是当前 Go 项目静态检查的事实标准——golint 已归档、go vet 默认漏检高危项、staticcheck 单独跑容易路径报错,三者手动拼凑只会增加维护成本和配置盲区。
为什么 go vet 单独跑基本等于没查
默认只开 printf、structtag 等几个检查器,像 unmarshal(json.Unmarshal(b, &v) 传值不传指针)、copylocks(sync.WaitGroup 值拷贝)、atomic(非 unsafe 下误用原子操作)全被关着。你写错 json.Unmarshal(b, v),go vet ./ 安静退出,但运行时 panic。
- 确认是否启用关键检查:看
.golangci.yml里有没有linters-settings.govet.checks: ["all"](Go 1.21+ 支持)或至少显式列出["printf", "unmarshal", "copylocks", "atomic"] - 不要信
go vet -h输出的 “available analyzers” 列表——那是全部内置项,不是默认开启项 - 在模块根目录外执行
go vet ./可能因go list解析失败而跳过子包,安静无输出
golangci-lint 配置必须改的三处
生成的默认 .golangci.yml 几乎不能用。不改这三项,90% 的隐患照常漏过:
- 删掉或禁用
golint:linters.disable: ["golint"]—— 它已归档,且不支持泛型、不检查死代码、规则主观 - 强制启用
staticcheck全量检查:linters-settings.staticcheck.checks: ["all"]或至少加"SA1019"(弃用 API)、"SA4006"(恒真/恒假判断) - 打开
errcheck的类型断言检查:errcheck.check-type-assertions: true—— 否则_, ok := x.(T)忽略ok不报警
CI 和本地行为不一致?先盯住 GO111MODULE 和路径
golangci-lint run 在 CI 报一堆 SA1019,本地却安静?大概率是环境漂移:
-
GO111MODULE=off时,go list -deps解析失败,linter 直接跳过依赖分析,大量语义检查失效 -
.golangci.yml没放在go.mod所在目录(monorepo 中常见),工具找不到模块上下文,退化为文件级扫描 - CI 脚本没传
--config=.golangci.yml,它就用默认配置,staticcheck和govet全部半残 - 构建标签不一致:
go vet -tags=unit ./和 CI 的-tags=ci看到的代码不同,字段/方法可能被条件编译掉
最易被忽略的一点:golangci-lint 不是“装完就能用”,它的有效性完全取决于配置是否落在模块根目录、GO111MODULE 是否为 on、以及 checks: ["all"] 是否真正生效——缺一不可。任何一项出错,都表现为“零输出”或“只报风格问题”。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











