go vet 能抓到编译器放过的一类错误:格式串和参数不匹配、拷贝了锁、忘了调用 cancel。这篇写一个包含十几种典型错误的文件,看 vet 逐条报了什么,漏了什么,并验证 go test 里自带的那份 vet 只是它的一小部分。
退出码 1;共 16 条报告:
v.go:27:2: the cancel function is not used on all paths (possible context leak)
v.go:32:1: this return statement may be reached without using the cancel var defined on line 27
v.go:74:2: result of fmt.Sprintf call not used
v.go:81:10: WaitGroup.Add called from inside new goroutine
v.go:56:33: redundant or: a == 1 || a == 1
v.go:70:9: second argument to errors.As must be a non-nil pointer to either a type that implements error, or to any interface type
v.go:62:8: using resp before checking for errors
v.go:19:14: fmt.Printf format %d has arg "字符串" of wrong type string
v.go:20:2: fmt.Println arg list ends with redundant newline
v.go:21:17: fmt.Printf format %s reads arg #2, but call has 1 arg
v.go:54:36: x (32 bits) too small for shift of 40
v.go:58:36: conversion from int to string yields a string of one rune, not a string of digits
v.go:49:3: struct field tag `json: "b"` not compatible with reflect.StructTag.Get: bad syntax for struct tag value
v.go:42:2: unreachable code
v.go:36:2: self-assignment of x
v.go:24:17: CopyLock passes lock by value: lab.T contains sync.Mutex格式串与参数不符、Println 末尾多一个换行、拷贝含 Mutex 的结构体、cancel 没在所有路径上调用、WaitGroup.Add 写在 goroutine 里面、string(int)、位移超过类型宽度、errors.As 第二个参数不是指针、在检查 err 之前就用 resp……都被 vet 指出了位置和原因。重复的 json tag key 没有被报告,所以 vet 不是完备的。
go tool vet help 列出的检查器共 35 个:appends asmdecl assign atomic bools buildtag cgocall composites copylocks defers directive errorsas framepointer hostport httpresponse ifaceassert loopclosure lostcancel nilfunc printf shift sigchanyzer slog stdmethods stdversion stringintconv structtag testinggoroutine tests timeformat unmarshal unreachable unsafeptr unusedresult waitgroup
vet 要代码能通过类型检查。我第一次写的文件里有“声明了 cancel 没使用”和“缺少 return”两个编译错误,vet 只报了这一条编译错误就停了,后面的检查一条都没跑。
只有 printf 问题和 copylocks 问题时 go test:退出码 1;FAIL lab [build failed] | FAIL | # lab | # [lab] | ./v.go:15:29: fmt.Printf format %d has arg "字符串" of wrong type string 只有 copylocks 问题时 go test:退出码 0;ok lab 0.102s 同样的代码 go vet:退出码 1;v.go:10:17: CopyLock passes lock by value: lab.T contains sync.Mutex
go test 会先跑一个高置信度子集(11 个检查器),发现问题就不运行测试。实验里同时有 printf 和 copylocks 问题时,go test 以 printf 问题失败;只有 copylocks 问题时,go test 通过,go vet 却失败。所以持续集成里要单独跑 go vet ./...。
As part of building a test binary, go test runs go vet on the package and its test source files to identify significant problems. If go vet finds any problems, go test reports those and does not run the test binary. Only a high-confidence subset of the default go vet checks are used. That subset is: atomic, bools, buildtag, directive, errorsas, ifaceassert, nilfunc, printf, stdversion, stringintconv, and tests. You can see the documentation for these and other vet tests via "go doc cmd/vet". To disable the running of go vet, use the -vet=off flag.
go help test 列出的子集是 atomic、bools、buildtag、directive、errorsas、ifaceassert、nilfunc、printf、stdversion、stringintconv、tests,-vet=off 可关闭。