go vet中的那些检测项(1)

简介: go vet中的那些检测项(1)

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] 形式的分配。 这些几乎总是无用的,即使没有用,它们通常也是一个错误。


assigngo vet 中的一个检查项,主要用于检查可能出现的变量赋值问题。

具体来说,assign 检查的是在变量赋值时可能出现的问题,比如:

  1. 将变量赋值给自身,例如 x = x
  2. 在多重赋值中,左边的变量数量和右边的值数量不一致;
  3. 将一个值赋给一个不兼容的变量类型,例如将一个字符串赋给一个整型变量;
  4. ifforswitch 等语句中,将一个值赋给一个布尔型变量而不是比较表达式;
  5. 在赋值语句中,使用了未定义的变量。

微信截图_20230925150837.png

以下是一些示例代码,展示了 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 检查项主要用于检查在使用原子操作时可能出现的一些问题。

微信截图_20230925151004.png

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 安全地访问共享变量。

具体来说,这段代码分别展示了以下几种情况:

  1. 直接赋值给原子变量:x = atomic.AddUint64(&x, 1)
  2. 左侧包含其他变量的赋值语句:_, x = 10, atomic.AddUint64(&x, 1)x, _ = atomic.AddUint64(&x, 1), 10
  3. 通过指针访问原子变量:*y = atomic.AddUint64(y, 1)
  4. 在结构体中定义的原子变量:su.Counter = atomic.AddUint64(&su.Counter, 1)
  5. 在结构体中定义的指针类型的原子变量:*sp.Counter = atomic.AddUint64(sp.Counter, 1)
  6. 在切片中访问原子变量:au[0] = atomic.AddUint64(&au[0], 1)
  7. 在指针切片中访问原子变量:*ap[0] = atomic.AddUint64(ap[0], 1)

在这些情况中,go vetatomic 检查器会给出警告,提醒程序员需要使用原子操作来保证多个 goroutine 安全地访问共享变量。正确的做法是使用原子操作函数的返回值,而不是将原子操作的结果再次赋值给变量。




4. atomicalign (未集成)


check for non-64-bits-aligned arguments to sync/atomic functions

atomicalign 包定义了一个分析器,用于检查 sync/atomic 函数的非 64 位对齐参数。 在非 32 位平台上,如果这些函数的参数变量不是 64 位对齐,则会出现错误。 因此,调用者有责任安排此类变量的 64 位对齐。

请参阅golang.org/pkg/sync/at…




5. bools


detects common mistakes involving boolean operators

-bools 分析器会检查以下几种常见的布尔表达式错误:

  • 在布尔表达式中使用了非布尔类型的值;
  • 在布尔表达式中使用了常量 truefalse,但该常量实际上不是布尔类型;
  • 在布尔表达式中使用了多余的括号。

微信截图_20230925151113.png

更多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.Mutexsync.RWMutex

在 Go 语言中,sync.Mutexsync.RWMutex 是用于保护共享资源的常用同步原语。使用这些类型的互斥锁来保护共享资源时,需要确保在访问这些资源时正确地加锁和解锁。如果在访问共享资源时没有正确地加锁和解锁,可能会导致数据竞争和其他并发问题。

copylocks 分析器会检查以下问题:

  • 在使用 sync.Mutexsync.RWMutex 时,是否正确地保护了共享资源,并在访问这些资源时正确地加锁和解锁。
  • 在使用 sync.Mutexsync.RWMutex 时,是否正确地处理了复制和移动操作。例如,如果一个值包含一个互斥锁,那么复制或移动该值可能会导致锁的状态不正确。

go vet 命令行上,可以使用 -copylocks 标志来控制是否执行 copylocks 分析器。默认情况下,copylocks 分析器是开启的。如果您不需要检查 sync.Mutexsync.RWMutex 的使用,可以使用 -copylocks=false 来禁用它。

总之,copylocks 分析器可以帮助您编写更健壮的并发程序,确保在访问共享资源时正确地加锁和解锁,并处理复制和移动操作时正确地处理互斥锁的状态。


go vet 是 Go 语言的一个静态分析工具,它可以帮助开发者检查代码中可能存在的错误。其中,copylocksgo vet 的一个检查规则,它的作用是检查是否复制了值含有锁或原子类型的值。

当你复制一个包含锁(如 sync.Mutexsync.WaitGroup)或原子类型(如 sync/atomic 包中的类型)的值时,可能会导致一些非常微妙的错误。例如,如果你复制一个 sync.Mutex,你可能会得到一个未锁定的新 Mutex,这可能会导致数据竞争或其他并发问题。同样,复制一个包含原子类型的值也可能导致类似的问题。

以下是一个简单的实例,演示了 go vetcopylocks 检查如何工作:

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 vetcopylocks 检查希望避免的。

如果你运行 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 vetcopylocks 检查是一个非常有用的工具,可以帮助你避免一些可能非常微妙和难以调试的并发问题。

微信截图_20230925151440.png

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 是一个非常有用的工具,可以帮助开发人员发现代码中可能存在的控制流问题。

微信截图_20230925151734.png

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 的第二个参数是否是指向实现错误的类型的指针

1.19新增

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 函数报告错误。


目录
相关文章
|
6月前
|
缓存 算法 安全
浅谈go垃圾回收与竞争检测
【5月更文挑战第16天】Go语言的运行时聚焦于垃圾回收(GC)和并发特性。GC通过微小和小对象分配器管理内存,大于32KB的大对象直接分配。GC是并发的,使用写屏障和非压缩策略,分为扫描终止、标记、标记终止和扫除四个阶段。竞争检测用于查找数据竞争,debug包提供运行时调试功能,如堆栈跟踪。内部的atomic包提供原子操作保证线程安全,math包检测数学溢出。sys包包含系统特定常量,NotInHeap结构确保某些对象不被GC管理。
69 5
浅谈go垃圾回收与竞争检测
|
6月前
|
数据可视化 Java 测试技术
【Go语言专栏】Go语言中的内存泄漏检测与修复
【4月更文挑战第30天】Go语言内存泄漏详解:概念、原因、检测与修复。内存泄漏由忘记释放内存、循环引用等引起,Go通过垃圾回收机制管理内存,但仍有泄漏风险。检测方法包括pprof、可视化工具、代码审查和单元测试。修复策略涉及优化代码、使用defer、减少全局变量、弱引用及及时释放资源。实践案例分析有助于理解和解决问题。了解内存管理,防止泄漏,提升Go应用性能和稳定性。
317 0
|
XML JSON Rust
go vet中的那些检测项(2)
go vet中的那些检测项(2)
226 0
|
机器学习/深度学习 传感器 算法
基于matlab实现GO-CFAR干扰目标背景下检测性能仿真
基于matlab实现GO-CFAR干扰目标背景下检测性能仿真
|
9天前
|
存储 JSON 监控
Viper,一个Go语言配置管理神器!
Viper 是一个功能强大的 Go 语言配置管理库,支持从多种来源读取配置,包括文件、环境变量、远程配置中心等。本文详细介绍了 Viper 的核心特性和使用方法,包括从本地 YAML 文件和 Consul 远程配置中心读取配置的示例。Viper 的多来源配置、动态配置和轻松集成特性使其成为管理复杂应用配置的理想选择。
30 2
|
Go Linux
golang使用vet进行语法检查
golang vet工具的使用 一般来说每一门语言都有一些用来进行语法检查的工具,vet就是golang中提供的语法检查工具,可以让我检查出package或者源码文件中一些隐含的错误,规范我们的项目代码,下面我简单讲解下该工具的使用.
7997 0
|
8天前
|
Go 索引
go语言中的循环语句
【11月更文挑战第4天】
19 2
|
8天前
|
Go C++
go语言中的条件语句
【11月更文挑战第4天】
21 2
|
12天前
|
程序员 Go
go语言中的控制结构
【11月更文挑战第3天】
88 58
|
3天前
|
Go API 数据库
Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
本文介绍了 Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
16 4