go vet 是什么
go vet 是 Go 官方静态分析工具,在编译前检查代码中的潜在错误和不规范写法。它不是编译器(不查类型错误),也不是 linter(不查风格),而是专门盯”几乎肯定是 bug”的模式——所以它的报告通常值得认真对待。
核心检查项
类型与格式化
- 格式化字符串:
Printf系列的占位符与参数类型不匹配(如%d给了 string); - 类型转换:可疑转换(如
string(int)——会把整数转成对应码点的字符,Go 1.15+ 起 vet 会警告); - 未使用/无效代码:未使用的变量导入(编译器已管)、
return后的不可达代码。
并发与资源
- 锁复制:
sync.Mutex等锁被按值复制(如方法接收者用了值类型),导致锁状态不一致; - 原子操作误用:对 atomic 变量直接赋值/读取而不是用原子函数;
- context 取消泄漏:
context.WithCancel返回的 cancel 函数没被调用。
代码规范
- 循环闭包陷阱:goroutine 中引用循环变量(Go 1.22 前是经典 bug 源);
- 结构体标签:
json:"name"等 tag 是否符合 reflect.StructTag 规范; - 变量遮蔽(-shadow):内层声明意外遮蔽外层变量。
使用方式
go vet ./... # 检查当前模块
go vet main.go # 单个文件
go vet -v ./... # 详细输出
# 常用参数
go vet -shadow ./... # 开启变量遮蔽检查
go vet -tests ./... # 连同测试文件一起检查
go vet -printf=false # 关闭某类检查
实际案例
// 案例1:格式化字符串错误
s := "hello"
fmt.Printf("%dn", s)
// vet 输出: Printf format %d has arg s of wrong type string
// 案例2:锁被值复制
type Foo struct { lock sync.Mutex }
func (f Foo) Lock() {} // 错误:值接收者复制了锁
// vet 输出: Lock passes lock by value
// 修复: func (f *Foo) Lock() {}
// 案例3:cancel 未调用
ctx, _ := context.WithCancel(context.Background())
// vet 输出: the cancel function should be called
// 修复: ctx, cancel := context.WithCancel(...); defer cancel()
局限性
- 是启发式检查,个别报告可能是误报(如 -shadow 在刻意遮蔽时的场景);
- 不覆盖业务逻辑错误;并发问题中的数据竞争需要
-race(运行时检测),两者互补:vet 管静态、race 管动态。
版本演进
Go 1.12 起 vet 重构为模块化分析框架,支持自定义分析器;新版本持续增加检查项。工程上还可以配合 staticcheck(社区分析器)一起用,并集成到 CI:go vet ./... && go test ./...。


