package main
import "fmt"
func customLogf(str string, args ...interface{}) {
fmt.Printf(str, args...)
}
func main() {
i := 42
customLogf("the answer is %s\n", i)
}
$ go tool vet custom-printf-func.go
$ go tool vet -printfuncs customLogf custom-printf-func.go
custom-printf-func.go:11: arg i for printf verb %s of wrong type: int
你可以看到如果没有-printfuncs选项,vet没有任何输出。
3.2 Boolean错误
vet可以检查一直为true、false或者冗余的表达式。
package main
import "fmt"
func main() {
var i int
// always true
fmt.Println(i != 0 || i != 1) // always false
fmt.Println(i == 0 && i == 1) // redundant check
fmt.Println(i == 0 && i == 0)
}
$ go vet bool-expr.go
bool-expr.go:9: suspect or: i != 0 || i != 1
bool-expr.go:12: suspect and: i == 0 && i == 1
bool-expr.go:15: redundant and: i == 0 && i == 0
这种类型的警告常常是非常危险的,可以引起讨厌的bug。大多数情况下是由于排版错误引起的。
3.3 Range循环
当读取变量的时候,在range块内的go协程可能是有问题的。在这些场景下,vet可以检测到它们:
package main
import "fmt"
func main() {
words := []string{"foo", "bar", "baz"}
for _, word := range words {
go func() {
fmt.Println(word)
}()
}
}
$ go tool vet range.go
range.go:10: range variable word captured by func literal
3.4 Unreachable的代码
下面的例子包含3个函数,带有不能到达的代码,每个函数使用了不同的方式。
package main
import "fmt"
func add(a int, b int) int {
return a + b
fmt.Println("unreachable")
return 0
}
func div(a int, b int) int {
if b == 0 {
panic("division by 0")
} else {
return a / b
}
fmt.Println("unreachable")
return 0
}
func fibonnaci(n int) int {
switch n {
case 0: return 1
case 1: return 1
default: return fibonnaci(n-1) + fibonnaci(n-2)
}
fmt.Println("unreachable")
return 0
}
func main() {
fmt.Println(add(1, 2))
fmt.Println(div(10, 2))
fmt.Println(fibonnaci(5))
}
$ go vet unreachable.go
unreachable.go:8: unreachable code
unreachable.go:19: unreachable code
unreachable.go:33: unreachable code
3.5 混杂的错误
这里是一个代码段,包含了其他的几个vet可以检测的混杂的错误:
package main
import (
"fmt"
"log"
"net/http"
)
func f() {}
func main() { // Self assignment
i := 42
i = i // a declared function cannot be nil
fmt.Println(f == nil) // shift too long
fmt.Println(i >> 32) // res used before checking err
res, err := http.Get("https://www.spreadsheetdb.io/")
defer res.Body.Close()
if err != nil {
log.Fatal(err)
}
}
$ go tool vet misc.go
misc.go:14: self-assignment of i to i
misc.go:17: comparison of function f == nil is always false
misc.go:20: i might be too small for shift of 32
misc.go:24: using res before checking for errors
3.6 误报和漏报
有时,vet可能忽略了错误,并警告可疑代码,这些代码实际上是正确的。下面的例子:
package main
import "fmt"
func main() {
rate := 42
// this condition can never be true
if rate > 60 && rate < 40 {
fmt.Println("rate %:", rate)
}
}
$ go tool vet false.go
false.go:10: possible formatting directive in Println call