go vet 是专查“合法但可疑”代码的静态分析工具,不参与编译、不报语法或类型错误;默认仅启用 printf、structtag、unreachable 等少数检查项,需手动开启 -unmarshal、-copylocks 等关键选项才能覆盖高危模式。

go vet 不是编译期错误检测工具,它不参与编译流程,也不报告语法或类型错误——那些由 go build 负责。它只在代码合法的前提下,揪出“大概率会出问题”的写法。
go vet 报的不是编译错误,而是语义可疑模式
它不检查 undefined: xxx 或 cannot use yyy (type int) as type string 这类编译器报错。它的目标更窄也更关键:
-
fmt.Printf("%s", 42)→ 报Printf format %s has arg 42 of wrong type int(参数类型错,但能编译) -
json.Unmarshal(data, s),其中s是结构体值而非指针 → 报unmarshal: cannot unmarshal into non-pointer(能编译,但运行时静默失败) -
for _, v := range items { go func() { use(v) }() }→ 默认不报,但加-loopexit或用staticcheck可捕获变量复用(逻辑错,非语法错)
哪些“能编译但危险”的问题,go vet 默认就管
无需额外开关,这些检查已启用(Go 1.21+):
-
printf:格式串动词与参数不匹配(如fmt.Printf("hello", name)缺%s) -
structtag:JSON/XML 标签拼写错误、非法字符、未导出字段配了json:"x" -
unreachable:return或panic后还有语句(说明控制流有断裂) -
copylocks:把含sync.Mutex的结构体值传给函数(锁操作作用于副本)
注意:copylocks 在 Go 1.20+ 才默认开;老版本必须显式加 -copylocks。
立即学习“go语言免费学习笔记(深入)”;
为什么 go vet ./ 没报错,但上线后 panic 了
常见盲区有三个:
- 没启用关键检查项:比如
-unmarshal(查json.Unmarshal非指针)、-atomic(查sync/atomic类型误用),默认关闭 - 构建标签不一致:CI 用
go vet -tags=ci ./,但本地开发用go vet -tags=dev ./,导致部分字段/方法在 CI 中不可见,漏检 - 第三方包干扰:
go vet ./会扫 vendor 和依赖包,它们触发规则就失败;应排除:go vet $(go list ./ | grep -v '/vendor\|golang.org/x/')
CI 中跑 go vet 的最小可靠命令
别信“一键全量”,要稳定就得约束范围和行为:
- 固定 Go 版本:CI 镜像必须和本地开发一致(不同 Go 版本的 vet 规则有差异)
- 显式启用核心项:
go vet -unmarshal -atomic -composites -printfuncs=Infof,Warnf,Errorf -tags=ci ./ - 排除干扰路径:用
go list过滤,避免第三方包拖垮结果 - 注意 Windows 路径:CI 若跑在 Windows 上,加
GOOS=linux避免路径解析异常
真正容易被忽略的,是构建标签和包可见性——同一行代码,在 -tags=unit 下可能根本不会被 vet 看到,也就永远不会报警。


















