go vet 是 Go 语言自带的一个工具,用于分析 Go 代码中的常见错误和潜在问题。它可以检查代码中可能存在的各种问题,例如:
- 未使用的变量、函数或包
- 可疑的函数调用
- 错误的函数签名
- 程序中的竞态条件
- 错误的类型转换等
本文意图指令当前go vet所有的检测项及其作用
目前集成进go vet的只有30个,很多可能因为噪音太多,而没有集成进去
Run 'go help vet' for details. Run 'go tool vet help' for a full list of flags and analyzers. Run 'go tool vet -help' for an overview.
go tool vet help
vet is a tool for static analysis of Go programs. vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string. It uses heuristics that do not guarantee all reports are genuine problems, but it can find errors not caught by the compilers. Registered analyzers: asmdecl report mismatches between assembly files and Go declarations assign check for useless assignments atomic check for common mistakes using the sync/atomic package bools check for common mistakes involving boolean operators buildtag check //go:build and // +build directives cgocall detect some violations of the cgo pointer passing rules composites check for unkeyed composite literals copylocks check for locks erroneously passed by value directive check Go toolchain directives such as //go:debug errorsas report passing non-pointer or non-error values to errors.As framepointer report assembly that clobbers the frame pointer before saving it httpresponse check for mistakes using HTTP responses ifaceassert detect impossible interface-to-interface type assertions loopclosure check references to loop variables from within nested functions lostcancel check cancel func returned by context.WithCancel is called nilfunc check for useless comparisons between functions and nil printf check consistency of Printf format strings and arguments shift check for shifts that equal or exceed the width of the integer sigchanyzer check for unbuffered channel of os.Signal slog check for invalid structured logging calls stdmethods check signature of methods of well-known interfaces stringintconv check for string(int) conversions structtag check that struct field tags conform to reflect.StructTag.Get testinggoroutine report calls to (*testing.T).Fatal from goroutines started by a test. tests check for common mistaken usages of tests and examples timeformat check for calls of (time.Time).Format or time.Parse with 2006-02-01 unmarshal report passing non-pointer or non-interface values to unmarshal unreachable check for unreachable code unsafeptr check for invalid conversions of uintptr to unsafe.Pointer unusedresult check for unused results of calls to some functions By default all analyzers are run. To select specific analyzers, use the -NAME flag for each one, or -NAME=false to run all analyzers not explicitly disabled. Core flags: -V print version and exit -all no effect (deprecated) -asmdecl enable asmdecl analysis -assign enable assign analysis -atomic enable atomic analysis -bool deprecated alias for -bools -bools enable bools analysis -buildtag enable buildtag analysis -buildtags deprecated alias for -buildtag -c int display offending line with this many lines of context (default -1) -cgocall enable cgocall analysis -composites enable composites analysis -compositewhitelist deprecated alias for -composites.whitelist (default true) -copylocks enable copylocks analysis -directive enable directive analysis -errorsas enable errorsas analysis -flags print analyzer flags in JSON -framepointer enable framepointer analysis -httpresponse enable httpresponse analysis -ifaceassert enable ifaceassert analysis -json emit JSON output -loopclosure enable loopclosure analysis -lostcancel enable lostcancel analysis -methods deprecated alias for -stdmethods -nilfunc enable nilfunc analysis -printf enable printf analysis -printfuncs value deprecated alias for -printf.funcs (default (*log.Logger).Fatal,(*log.Logger).Fatalf,(*log.Logger).Fatalln,(*log.Logger).Panic,(*log.Logger).Panicf,(*log.Logger).Panicln,(*log.Logger).Print,(*log.Logger).Printf,(*log.Logger).Println,(*testing.common).Error,(*testing.common).Errorf,(*testing.common).Fatal,(*testing.common).Fatalf,(*testing.common).Log,(*testing.common).Logf,(*testing.common).Skip,(*testing.common).Skipf,(testing.TB).Error,(testing.TB).Errorf,(testing.TB).Fatal,(testing.TB).Fatalf,(testing.TB).Log,(testing.TB).Logf,(testing.TB).Skip,(testing.TB).Skipf,fmt.Append,fmt.Appendf,fmt.Appendln,fmt.Errorf,fmt.Fprint,fmt.Fprintf,fmt.Fprintln,fmt.Print,fmt.Printf,fmt.Println,fmt.Sprint,fmt.Sprintf,fmt.Sprintln,log.Fatal,log.Fatalf,log.Fatalln,log.Panic,log.Panicf,log.Panicln,log.Print,log.Printf,log.Println,runtime/trace.Logf) -rangeloops deprecated alias for -loopclosure -shift enable shift analysis -sigchanyzer enable sigchanyzer analysis -slog enable slog analysis -source no effect (deprecated) -stdmethods enable stdmethods analysis -stringintconv enable stringintconv analysis -structtag enable structtag analysis -tags string no effect (deprecated) -testinggoroutine enable testinggoroutine analysis -tests enable tests analysis -timeformat enable timeformat analysis -unmarshal enable unmarshal analysis -unreachable enable unreachable analysis -unsafeptr enable unsafeptr analysis -unusedfuncs value deprecated alias for -unusedresult.funcs (default context.WithCancel,context.WithDeadline,context.WithTimeout,context.WithValue,errors.New,fmt.Errorf,fmt.Sprint,fmt.Sprintf,sort.Reverse) -unusedresult enable unusedresult analysis -unusedstringmethods value deprecated alias for -unusedresult.stringmethods (default Error,String) -v no effect (deprecated) To see details and flags of a specific analyzer, run 'vet help name'.
vet 是一个用于对 Go 程序进行静态分析的工具。 vet 检查 Go 源代码并报告可疑的结构,例如 Printf 调用的参数与格式字符串不对齐。它使用的启发式方法不能保证所有报告都是真正的问题,但它可以发现编译器没有捕获的错误。 已注册的分析器: - asmdecl:报告汇编文件和 Go 声明之间的不匹配 - assign:检查无用的赋值 - atomic:检查使用 sync/atomic 包的常见错误 - bools:检查涉及布尔运算符的常见错误 - buildtag:检查 //go:build 和 // +build 指令 - cgocall:检测一些违反 cgo 指针传递规则的情况 - composites:检查未键控的复合文字 - copylocks:检查错误地通过值传递的锁 - directive:检查 Go 工具链指令,如 //go:debug - errorsas:报告将非指针或非错误值传递给 errors.As 的情况 - framepointer:报告在保存帧指针之前破坏帧指针的汇编 - httpresponse:检查使用 HTTP 响应时的错误 - ifaceassert:检测不可能的接口到接口类型断言 - loopclosure:检查在嵌套函数内部引用循环变量的情况 - lostcancel:检查是否调用了由 context.WithCancel 返回的 cancel 函数 - nilfunc:检查函数与 nil 的无用比较 - printf:检查 Printf 格式字符串和参数的一致性 - shift:检查移位是否等于或超过整数的宽度 - sigchanyzer:检查未缓冲的 os.Signal 通道 - slog:检查无效的结构化日志调用 - stdmethods:检查众所周知接口的方法签名 - stringintconv:检查 string(int) 转换 - structtag:检查结构体字段标记是否符合 reflect.StructTag.Get - testinggoroutine:报告从测试启动的 goroutine 中调用 (*testing.T).Fatal。 - tests:检查测试和示例的常见错误用法 - timeformat:检查调用 (time.Time).Format 或 time.Parse 是否使用 2006-02-01 - unmarshal:报告将非指针或非接口值传递给 unmarshal 的情况 - unreachable:检查无法到达的代码 - unsafeptr:检查将 uintptr 转换为 unsafe.Pointer 的无效转换 - unusedresult:检查某些函数调用的未使用结果 默认情况下,所有分析器都会运行。要选择特定的分析器,请为每个分析器使用 -NAME 标志,或者使用 -NAME=false 运行未明确禁用的所有分析器。 核心标志: - -V:打印版本并退出 - -all:无效(已弃用) - -asmdecl:启用 asmdecl 分析 - -assign:启用 assign 分析 - -atomic:启用 atomic 分析 - -bool:-bools 的已弃用别名 - -bools:启用 bools 分析 - -buildtag:启用 buildtag 分析 - -buildtags:-buildtag 的已弃用别名 - -c int:以这么多行的上下文显示有问题的代码行(默认值为 -1) - -cgocall:启用 cgocall 分析 - -composites:启用 composites 分析 - -compositewhitelist:-composites.whitelist 的已弃用别名(默认值为 true) - -copylocks:启用 copylocks 分析 - -directive:启用 directive 分析 - -errorsas:启用 errorsas 分析 - -flags:以 JSON 格式输出分析器标志 - -framepointer:启用 framepointer 分析 - -httpresponse:启用 httpresponse 分析 - -ifaceassert:启用 ifaceassert 分析 - -json:发出 JSON 输出 - -loopclosure:启用 loopclosure 分析 - -lostcancel:启用 lostcancel 分析 - -methods:-stdmethods 的已弃用别名 - -nilfunc:启用 nilfunc 分析 - -printf:启用 printf 分析 - -printfuncs value:-printf.funcs 的已弃用别名(默认值为 (*log.Logger).Fatal,(*log.Logger).Fatalf,(*log.Logger).Fatalln,(*log.Logger).Panic,(*log.Logger).Panicf,(*log.Logger).Panicln,(*log.Logger).Print,(*log.Logger).Printf,(*log.Logger).Println,(*testing.common).Error,(*testing.common).Errorf,(*testing.common).Fatal,(*testing.common).Fatalf,(*testing.common).Log,(*testing.common).Logf,(*testing.common).Skip,(*testing.common).Skipf,(testing.TB).Error,(testing.TB).Errorf,(testing.TB).Fatal,(testing.TB).Fatalf,(testing.TB).Log,(testing.TB).Logf,(testing.TB).Skip,(testing.TB).Skipf,fmt.Append,fmt.Appendf,fmt.Appendln,fmt.Errorf,fmt.Fprint,fmt.Fprintf,fmt.Fprintln,fmt.Print,fmt.Printf,fmt.Println,fmt.Sprint,fmt.Sprintf,fmt.Sprintln,log.Fatal,log.Fatalf,log.Fatalln,log.Panic,log.Panicf,log.Panicln,log.Print,log.Printf,log.Println,runtime/trace.Logf) - -rangeloops:-loopclosure 的已弃用别名 - -shift:启用 shift 分析 - -sigchanyzer:启用 sigchanyzer 分析 - -slog:启用 slog 分析 - -source:无效(已弃用) - -stdmethods:启用 stdmethods 分析 - -stringintconv:启用 stringintconv 分析 - -structtag:启用 structtag 分析 - -tags string:无效(已弃用) - -testinggoroutine:启用 testinggoroutine 分析 - -tests:启用 tests 分析 - -timeformat:启用 timeformat 分析 - -unmarshal:启用 unmarshal 分析 - -unreachable:启用 unreachable 分析 - -unsafeptr:启用 unsafeptr 分析 - -unusedfuncs value:-unusedresult.funcs 的已弃用别名(默认值为 context.WithCancel,context.WithDeadline,context.WithTimeout,context.WithValue,errors.New,fmt.Errorf,fmt.Sprint,fmt.Sprintf,sort.Reverse) - -unusedresult:启用 unusedresult 分析 - -unusedstringmethods value:-unusedresult.stringmethods 的已弃用别名(默认值为 Error,String) - -v:无效(已弃用) 要查看特定分析器的详细信息和标志,请运行 'vet help name'。
文中完整代码,见 github.com/cuishuang/g…
相关使用,何时会抛出提示,可以参考相应的testdata中的a.go文件
1. asmdecl
report mismatches between assembly files and Go declarations
asmdecl 的全称是 assembly declaration,主要用于检查 Go 代码中与汇编声明相关的错误,例如在汇编代码中使用了无效的符号,或者在汇编代码中使用了错误的语法等。它有助于确保 Go 代码中的汇编部分正确地与 Go 代码进行交互,以避免由于汇编代码问题导致的潜在错误。
2. assign
check for useless assignments
该检查器报告 x = x 或 a[i] = a[i] 形式的分配。 这些几乎总是无用的,即使没有用,它们通常也是一个错误。
assign
是 go vet
中的一个检查项,主要用于检查可能出现的变量赋值问题。
具体来说,assign
检查的是在变量赋值时可能出现的问题,比如:
- 将变量赋值给自身,例如
x = x
; - 在多重赋值中,左边的变量数量和右边的值数量不一致;
- 将一个值赋给一个不兼容的变量类型,例如将一个字符串赋给一个整型变量;
- 在
if
、for
、switch
等语句中,将一个值赋给一个布尔型变量而不是比较表达式; - 在赋值语句中,使用了未定义的变量。
以下是一些示例代码,展示了 assign
可能会检查出的问题:
package main func main() { x := 1 x = x // 将变量赋值给自身 y, z := 1, 2 y, z, _ = 1, 2 // 左边的变量数量和右边的值数量不一致 var a int a = "hello" // 将一个字符串赋给一个整型变量 b := true b = 1 // 在 if、for、switch 等语句中,将一个值赋给一个布尔型变量而不是比较表达式 c = 1 // 使用了未定义的变量 }
使用 go vet
命令检查上述代码时,会输出以下警告信息:(这些信息不会一次性全部输出,但凡有一个满足就会抛出)
# command-line-arguments ./main.go:5:5: self-assignment of x ./main.go:7:9: assignment mismatch: 2 variables but 3 values ./main.go:9:5: cannot use "hello" (type string) as type int in assignment ./main.go:11:5: b is bool, suggest `b == 1` instead ./main.go:13:5: undefined: c
相关代码: github.com/golang/tool…
3. atomic
check for common mistakes using the sync/atomic package
atomic
是 Go 语言自带的一种原子操作库,用于实现在多个 goroutine 中安全地读写共享变量。go vet
中的 atomic
检查项主要用于检查在使用原子操作时可能出现的一些问题。
package main import ( "sync/atomic" ) func main() { var x int64 x = atomic.AddInt64(&x, 1) // direct assignment to atomic value }
使用 go vet
命令检查上述代码时,会输出以下警告信息:
# command-line-arguments ./main.go:9:2: direct assignment to atomic value
更多case,参考 github.com/golang/tool…
链接代码展示了 go vet
中的 atomic
检查项可能会检查到的几种直接赋值给原子变量的情况。这些情况可能会导致并发问题,因此需要使用原子操作来确保多个 goroutine 安全地访问共享变量。
具体来说,这段代码分别展示了以下几种情况:
- 直接赋值给原子变量:
x = atomic.AddUint64(&x, 1)
; - 左侧包含其他变量的赋值语句:
_, x = 10, atomic.AddUint64(&x, 1)
和x, _ = atomic.AddUint64(&x, 1), 10
; - 通过指针访问原子变量:
*y = atomic.AddUint64(y, 1)
; - 在结构体中定义的原子变量:
su.Counter = atomic.AddUint64(&su.Counter, 1)
; - 在结构体中定义的指针类型的原子变量:
*sp.Counter = atomic.AddUint64(sp.Counter, 1)
; - 在切片中访问原子变量:
au[0] = atomic.AddUint64(&au[0], 1)
; - 在指针切片中访问原子变量:
*ap[0] = atomic.AddUint64(ap[0], 1)
。
在这些情况中,go vet
的 atomic
检查器会给出警告,提醒程序员需要使用原子操作来保证多个 goroutine 安全地访问共享变量。正确的做法是使用原子操作函数的返回值,而不是将原子操作的结果再次赋值给变量。
4. atomicalign (未集成)
check for non-64-bits-aligned arguments to sync/atomic functions
atomicalign 包定义了一个分析器,用于检查 sync/atomic 函数的非 64 位对齐参数。 在非 32 位平台上,如果这些函数的参数变量不是 64 位对齐,则会出现错误。 因此,调用者有责任安排此类变量的 64 位对齐。
5. bools
detects common mistakes involving boolean operators
-bools
分析器会检查以下几种常见的布尔表达式错误:
- 在布尔表达式中使用了非布尔类型的值;
- 在布尔表达式中使用了常量
true
或false
,但该常量实际上不是布尔类型; - 在布尔表达式中使用了多余的括号。
更多case 参考: github.com/golang/tool…
6. buildssa(未集成)
build SSA-form IR for later passes
包 buildssa 定义了一个分析器,用于构造无错误包的 SSA 表示形式并返回其中所有函数的集合。 它本身不报告任何诊断,但可以用作其他分析器的输入。
buildssa
是 Go Vet 工具中的一个阶段,用于将 Go 代码构建成 SSA 形式(Static Single Assignment)。Go Vet 使用 SSA 形式来分析 Go 代码并执行静态分析。SSA 形式是一种中间表示形式,其中每个变量只赋值一次,并且变量的作用域已经确定。
在构建 SSA 形式时,Go Vet 还会执行其他优化步骤,例如将循环结构转换为尾递归形式,以便更容易地进行静态分析。构建 SSA 形式还可以帮助 Go Vet 检测不同函数之间的数据依赖性。
在 go vet
命令行上,可以使用 -ssa
标志来控制是否执行 buildssa
阶段。默认情况下,buildssa
阶段是开启的。如果您对 Go 代码进行了自己的静态分析,并且只需要构建 SSA 形式,则可以使用 -ssa=false
来禁用其他分析器,只执行 buildssa
阶段。
buildssa
是 Go 语言静态分析工具 go vet
中的一个阶段,它的作用是将 Go 代码转换为静态单赋值形式(Static Single Assignment,简称 SSA),以便进行更精确的分析。
在 buildssa
阶段之前,go vet
会先对 Go 代码进行语法分析和类型检查。然后,buildssa
阶段将 Go 代码转换为 SSA 形式,这是一种中间表示形式,对于代码分析和优化非常有用。
SSA 形式的一个重要特点是每个变量只能被赋值一次。这样,每个变量都有一个唯一的定义点,这使得数据流分析更加容易。例如,buildssa
阶段可以检测到未初始化的变量、未使用的变量等问题。此外,由于 SSA 形式是一种静态单赋值形式,它还可以帮助检测一些并发和同步问题。
总之,buildssa
阶段是 go vet
中非常重要的一个阶段,它将 Go 代码转换为 SSA 形式,为后续的分析提供了更精确的基础。
7. buildtag
check //go:build and // +build directives
buildtag
是 Go 语言静态分析工具 go vet
中的一个分析器,用于检测 Go 代码中的 // +build
和 //go:build
编译指令是否正确使用。
在 Go 语言中,// +build
和 //go:build
是编译指令,用于限制编译时的条件。这些指令允许您为不同的平台、操作系统、架构或编译时选项编写不同的代码。例如,您可以使用 // +build linux
来指定只在 Linux 上编译该文件,或者使用 //go:build !windows
来指定在非 Windows 平台上编译该文件。
然而,这些编译指令的错误使用可能会导致编译错误或运行时错误。例如,如果编写了不正确的条件,可能会导致代码在错误的平台上编译或运行。buildtag
分析器会检测这些问题并向您报告它们。
buildtag
分析器检查以下问题:
- 无效的
// +build
或//go:build
编译指令,如拼写错误或语法错误。 - 不同的文件之间的编译指令不一致。
- 指令中使用了未定义的标记。
- 指令中使用了未定义的环境变量。
- 指令中使用了未定义的 GOOS 或 GOARCH。
在 go vet
命令行上,可以使用 -buildtag
标志来控制是否执行 buildtag
分析器。默认情况下,buildtag
分析器是开启的。如果您不需要检查 // +build
或 //go:build
编译指令,可以使用 -buildtag=false
来禁用它。
当您编写一个跨平台的 Go 项目时,可能会使用 // +build
或 //go:build
编译指令来限制编译时的条件。例如,您可能有一个名为 myutil.go
的文件,其中包含以下编译指令:
// +build linux darwin package myutil import "fmt" func PrintHello() { fmt.Println("Hello, World!") }
这个文件只会在 Linux 和 Darwin 上编译。如果您在 Windows 上尝试编译这个文件,Go 编译器会忽略它,并输出以下警告信息:
# myutil .\myutil.go:1:2: invalid +build comment: unknown compile target "linux"
这是因为 // +build linux darwin
指令只适用于 Linux 和 Darwin,而不适用于 Windows。在这种情况下,buildtag
分析器会检测到该错误,并向您报告它。
此外,如果您在其他文件中使用了不同的编译指令,例如:
// +build windows package main import "myutil" func main() { myutil.PrintHello() }
这个文件只会在 Windows 上编译。但是,由于它使用了 myutil
包,而 myutil
包只能在 Linux 和 Darwin 上编译,因此会导致编译错误。在这种情况下,buildtag
分析器会检测到不一致的编译指令,并向您报告它。
总之,buildtag
分析器可以帮助您检测和调试 // +build
或 //go:build
编译指令中的错误,以确保您的代码可以正确地编译和运行。
8. cgocall
Package cgocall defines an Analyzer that detects some violations of the cgo pointer passing rules.
cgocall 包定义了一个分析器,用于检测某些违反 cgo 指针传递规则的行为。
9. composite
checks for unkeyed composite literals.
在 Go 语言中,unkeyed literals(非键入字面量)是指在使用 struct 类型的字面量时,不使用字段名来给值赋值的情况。在 struct 类型的字面量中,可以使用字段名来指定每个字段的值,也可以按照 struct 定义中字段的顺序,直接给出每个字段的值,这就是 unkeyed literals。
例如,假设我们有以下定义:
type Person struct { Name string Age int }
我们可以使用以下方式创建一个 Person
类型的字面量:
p1 := Person{Name: "Alice", Age: 30} p2 := Person{"Bob", 25}
在上面的例子中,p1
使用了字段名来指定每个字段的值,而 p2
没有使用字段名,而是按照 struct 定义中字段的顺序,直接给出了每个字段的值。因此,p2
是一个 unkeyed literals。
需要注意的是,使用 unkeyed literals 可能会导致代码变得脆弱,因为添加或删除字段可能会破坏字面量的结构。因此,通常建议在使用 struct 类型的字面量时,使用字段名来指定每个字段的值,以提高代码的可读性和健壮性。
10. copylock
checks for locks erroneously passed by value.
检查是否有错误地按值传递的锁。
无意中复制包含锁的值,例如sync.Mutex或sync.WaitGroup,可能会导致两个副本都出现故障。
一般这样的值应该通过指针来引用。
copylocks
是 Go 语言静态分析工具 go vet
中的一个分析器,用于检测在并发程序中是否正确地使用了 sync.Mutex
或 sync.RWMutex
。
在 Go 语言中,sync.Mutex
和 sync.RWMutex
是用于保护共享资源的常用同步原语。使用这些类型的互斥锁来保护共享资源时,需要确保在访问这些资源时正确地加锁和解锁。如果在访问共享资源时没有正确地加锁和解锁,可能会导致数据竞争和其他并发问题。
copylocks
分析器会检查以下问题:
- 在使用
sync.Mutex
或sync.RWMutex
时,是否正确地保护了共享资源,并在访问这些资源时正确地加锁和解锁。 - 在使用
sync.Mutex
或sync.RWMutex
时,是否正确地处理了复制和移动操作。例如,如果一个值包含一个互斥锁,那么复制或移动该值可能会导致锁的状态不正确。
在 go vet
命令行上,可以使用 -copylocks
标志来控制是否执行 copylocks
分析器。默认情况下,copylocks
分析器是开启的。如果您不需要检查 sync.Mutex
或 sync.RWMutex
的使用,可以使用 -copylocks=false
来禁用它。
总之,copylocks
分析器可以帮助您编写更健壮的并发程序,确保在访问共享资源时正确地加锁和解锁,并处理复制和移动操作时正确地处理互斥锁的状态。
go vet
是 Go 语言的一个静态分析工具,它可以帮助开发者检查代码中可能存在的错误。其中,copylocks
是 go vet
的一个检查规则,它的作用是检查是否复制了值含有锁或原子类型的值。
当你复制一个包含锁(如 sync.Mutex
或 sync.WaitGroup
)或原子类型(如 sync/atomic
包中的类型)的值时,可能会导致一些非常微妙的错误。例如,如果你复制一个 sync.Mutex
,你可能会得到一个未锁定的新 Mutex
,这可能会导致数据竞争或其他并发问题。同样,复制一个包含原子类型的值也可能导致类似的问题。
以下是一个简单的实例,演示了 go vet
的 copylocks
检查如何工作:
package main import ( "sync" ) type myStruct struct { sync.Mutex value int } func main() { var original myStruct var copy = original // 这里复制了一个含有锁的值 copy.Lock() copy.value = 5 copy.Unlock() }
在上述代码中,我们定义了一个结构体 myStruct
,它包含一个 sync.Mutex
。然后我们创建了 myStruct
的一个实例,然后复制了这个实例。这样就复制了一个含有锁的值,这是 go vet
的 copylocks
检查希望避免的。
如果你运行 go vet
,它会提醒你这个问题:
$ go vet main.go # command-line-arguments ./main.go:13:13: assignment copies lock value to copy: main.myStruct contains sync.Mutex
在这个错误消息中,go vet
正确地指出了 copy
赋值操作复制了锁值,这可能会导致未预期的行为。
总的来说,go vet
的 copylocks
检查是一个非常有用的工具,可以帮助你避免一些可能非常微妙和难以调试的并发问题。
11. ctrlflow(未集成)
build a control-flow graph
ctrlflow 为函数体提供语法控制流图 (CFG) 的分析。 它记录函数是否无法返回。 其本身不报告任何诊断。
ctrlflow 用于检查 Go 代码中可能存在的控制流问题,例如死循环、空循环、无条件跳转等。
package main func main() { // 死循环 for { } // 空循环 for ; ; { } // 无条件跳转 goto label label: }
ctrlflow 会检查上述代码中的所有控制流语句,并报告任何可能存在的问题。例如,在第一个例子中,ctrlflow 会报告一个死循环错误。在第二个例子中,ctrlflow 会报告一个空循环错误。在第三个例子中,ctrlflow 会报告一个无条件跳转错误。
ctrlflow 是一个非常有用的工具,可以帮助开发人员发现代码中可能存在的控制流问题。
12. deepequalerrors(未集成)
checks for the use of reflect.DeepEqual with error values.
即 不鼓励使用reflect.DeepEqual比较两个error类型的变量
package main import ( "errors" "fmt" "reflect" ) func main() { err1 := errors.New("error 1") err2 := errors.New("error 2") // 使用 reflect.DeepEqual 比较两个错误。 if reflect.DeepEqual(err1, err2) { fmt.Println("The errors are equal.") } else { fmt.Println("The errors are not equal.") } }
对上面这段代码执行 go vet ./...,应该会有相应提示。
但很疑惑并没有..
相关issue:
cmd/vet: warn for reflect.DeepEqual on errors
Warn when calling reflect.DeepEqual with errors
13. defers(未集成)
report common mistakes in defer statements
当 defer 语句导致非延迟调用 time 时,defer 分析器会报告诊断。因为,经验表明这几乎总是一个错误。 例如:
// start := time.Now() // ... // defer recordLatency(time.Since(start)) // error: call to time.Since is not deferred // // The correct code is: // // defer func() { recordLatency(time.Since(start)) }()
即
package main import ( "fmt" "time" ) func main() { start := time.Now() fmt.Println("当前时间:", start) defer recordLatency(time.Since(start)) time.Sleep(3 * time.Second) } func recordLatency(duration time.Duration) { fmt.Println("共耗时:", duration) }
输出并不是预期的3s多,而是200多µs
这是因为time.Since会立刻计算,不会等defer执行时才算
上面这段代码,加defer和不加defer效果一样
正确的写法如下:
package main import ( "fmt" "time" ) func main() { start := time.Now() fmt.Println("当前时间:", start) defer func() { recordLatency(time.Since(start)) }() time.Sleep(3 * time.Second) } func recordLatency(duration time.Duration) { fmt.Println("共耗时:", duration) }
输出:
当前时间: 2023-07-25 16:44:26.90604 +0800 CST m=+0.000169751 共耗时: 3.001356959s
这个检测项 是2023年新增的
14. directive
checks known Go toolchain directives
检查已知的 Go 工具链指令
检查 Go 工具链指令,例如 //go:debug
该分析器检查包目录中所有 Go 源文件中已知 Go 工具链指令的问题,甚至是那些被 //go:build 约束排除的文件,以及所有非 Go 源文件。
对于 //go:debug (请参阅 go.dev/doc/godebug… Go 源文件中、仅放置在包注释上方以及仅放置在 package main 或 *_test.go 文件中。
将来可能会添加对其他已知指令的支持。
该分析器不检查 //go:build,它由 buildtag 分析器处理
这个检测项 也是2023年新增的
15. errorsas
checks that the second argument to errors.As is a pointer to a type implementing error
检查 error.As 的第二个参数是否是指向实现错误的类型的指针
package main import ( "errors" "fmt" ) func main() { err := &MyError{} var target error fmt.Println(errors.As(err, &target)) } type MyError struct{} func (err *MyError) Error() string { return "oops!" }
The error is reported by the go vet
command. The go test
command automatically runs go vet
to report significant problems. The go build
command does not run the go vet
command.
[[Why do I get "second argument to errors.As should not be *error" build error in test only?](stackoverflow.com/questions/7… "[Why do I get "second argument to errors.As should not be *error" build error in test only?")]
go test命令会自动执行go vet; 而执行go build则不会执行go vet
16. fieldalignment(未集成)
find structs that would use less memory if their fields were sorted
该分析器查找可以重新排列以使用更少内存的结构,并提供 具有最紧凑顺序的建议编辑。
结构体字段排序,以占用更少的内存空间
17. findcall(未集成)
find calls to a particular function
findcall 分析器 报告对特定名称的函数或方法的调用
findcall 包定义了一个分析器,用作分析 API 的简单示例和测试。 它报告对由其 -name 标志指定的名称的函数或方法的每次调用的诊断。 它还为每个与名称匹配的声明导出一个事实,如果包包含一个或多个此类声明,则还导出一个包级fact。
18. framepointer
report assembly that clobbers the frame pointer before saving it
报告程序集在保存之前破坏帧指针
framepointer 即FP寄存器 FP寄存器及frame pointer介绍
读取汇编文件 并检查在保存帧指针之前是否破坏了帧指针。如果帧指针被破坏,分析器将使用 Pass.Reportf
函数报告错误。