关于后端:go-vet中的那些检测项

12次阅读

共计 45323 个字符,预计需要花费 114 分钟才能阅读完成。

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'。

文中残缺代码,见 https://github.com/cuishuang/govet-demo

相干应用,何时会抛出提醒,能够参考相应的 testdata 中的 a.go 文件

1. asmdecl

<font color=”orange”>report mismatches between assembly files and Go declarations</font>

asmdecl 的全称是 assembly declaration,次要用于查看 Go 代码中与汇编申明相干的谬误,例如在汇编代码中应用了有效的符号,或者在汇编代码中应用了谬误的语法等。它有助于确保 Go 代码中的汇编局部正确地与 Go 代码进行交互,以防止因为汇编代码问题导致的潜在谬误。


2. assign

<font color=”orange”>check for useless assignments</font>

该查看器报告 x = x 或 a[i] = a[i] 模式的调配。这些简直总是无用的,即便没有用,它们通常也是一个谬误。

assigngo vet 中的一个查看项,次要用于查看可能呈现的变量赋值问题。

具体来说,assign 查看的是在变量赋值时可能呈现的问题,比方:

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

以下是一些示例代码,展现了 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

相干代码: https://github.com/golang/tools/blob/master/go/analysis/passes/assign/assign.go#L64


3. atomic

<font color=”orange”>check for common mistakes using the sync/atomic package</font>

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,参考 https://github.com/golang/tools/blob/master/go/analysis/passes/atomic/testdata/src/a/a.go

链接代码展现了 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 (未集成)

<font color=”orange”>check for non-64-bits-aligned arguments to sync/atomic functions</font>

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

请参阅 https://golang.org/pkg/sync/atomic/#pkg-note-BUG

<font color=”orange”> </font>


5. bools

<font color=”orange”>detects common mistakes involving boolean operators</font>

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

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

更多 case 参考: https://github.com/golang/tools/blob/master/go/analysis/passes/bools/testdata/src/a/a.go


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 查看是一个十分有用的工具,能够帮忙你防止一些可能十分奥妙和难以调试的并发问题。


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 工具链指令

<font color=”orange” size=1>

查看 Go 工具链指令,例如 //go:debug

该分析器查看包目录中所有 Go 源文件中已知 Go 工具链指令的问题,甚至是那些被 //go:build 束缚排除的文件,以及所有非 Go 源文件。

对于 //go:debug(请参阅 https://go.dev/doc/godebug),分析器查看指令是否仅搁置在 Go 源文件中、仅搁置在包正文上方以及仅搁置在 package main 或 *_test.go 文件中。

未来可能会增加对其余已知指令的反对。

该分析器不查看 //go:build,它由 buildtag 分析器解决

</font>

这个检测项 也是 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?]

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


19. httpresponse

check for mistakes using HTTP responses

应用 net/http 包时的一个常见谬误,是在查看确定响应是否无效的谬误之前应用 defer 提早敞开 http.Response Body 的函数调用:

    resp, err := http.Head(url)
    defer resp.Body.Close()
    if err != nil {log.Fatal(err)
    }
    // (defer statement belongs here)

该查看器通过报告此类谬误的诊断来帮忙发现潜在的 nil dereference bugs

nil dereference bugs 是什么?

nil dereference bugs 指的是试图拜访 null 或不是冀望对象的对象, 从而导致程序解体的 bug。

在某些语言中, 比方 Go 语言和 Rust 语言, 当尝试拜访 nil 指针时会触发 panic 或 panic。这能够帮忙发现编程谬误。

一个典型的 nil dereference bug 案例是:

var p *Person

p.Name // 解体, 因为 p 是 nil 指针

这里 p 是 nil 指针, 试图拜访 p.Name 就会导致 nil 指针援用谬误, 程序解体。

为防止 nil dereference bug, 咱们须要查看指针是否为 nil, 而后能力平安的拜访:

if p != nil {fmt.Println(p.Name)
}

所以总的来说,nil dereference bugs 就是因为未查看指针是否为 nil 从而导致的尝试拜访 nil 指针的谬误。

package main

import (
    "log"
    "net/http"
)

func main() {badHTTPGet()
}

func badHTTPGet() {res, err := http.Get("http://foo.com")   // 如果 err 不是 nil,则 res 为 nil,最初调用 res.Body.Close() 会 panic
  
    defer res.Body.Close() // want "using res before checking for errors"
    if err != nil {log.Fatal(err)
    }
}

更多 case,参考 https://github.com/golang/tools/blob/master/go/analysis/passes/httpresponse/testdata/src/a/a.go


20. ifaceassert

detect impossible interface-to-interface type assertions

此查看器标记类型断言 v.(T) 和相应的类型转换状况,其中 v 的动态类型 V 是不可能实现目标接口 T 的接口。当 V 和 T 蕴含具备雷同名称但不同签名的办法时,就会产生这种状况。

//    var v interface {//        Read()
//    }
//    _ = v.(io.Reader)

v 中的 Read 办法与 io.Reader 中的 Read 办法具备不同的签名,因而该断言无奈胜利。

package ifaceassert

type Foo interface {Bar()
}

type FooImpl struct{}

func (f *FooImpl) Bar() {}

type SomeType struct {
}

func main() {
    var f Foo
    f = &FooImpl{}

    f1 := f.(*FooImpl)  // 这是一个无效的类型断言
    f2 := f.(*SomeType) // 这是一个有效的类型断言
}

上面这两段仅供参考:

ifaceassert 是 go vet 的一个性能, 它用于查看接口值是否被无效断言。

举个例子:

type Foo interface {Bar()
}

type FooImpl struct{}

func (f *FooImpl) Bar() {}

func main() {
    var f Foo 
    f = &FooImpl{}
    
    f1 := f.(*FooImpl)  // 这是一个无效的类型断言
    f2 := f.(*SomeType) // 这是一个有效的类型断言    
}

这里咱们定义了一个 Foo 接口, 有一个 FooImpl 实现。
而后应用类型断言 (f.(*FooImpl)) 无效地断言了接口值。
然而 f.(*SomeType) 是有效的类型断言, 因为接口值理论类型不是*SomeType

go vet 的 ifaceassert 能够检测到这个谬误:

./main.go:17: invalid type assertion: f.(sometype.*SomeType) (non-interface type *FooImpl on left)

它通知咱们, 右边是 *FooImpl 类型, 然而咱们尝试断言为*SomeType, 这是有效的。

所以 ifaceassert 能够帮忙咱们查看类型断言是否无效, 防止因为有效类型断言而引起的 bug。
当然正确的写法是:

f1 := f.(*FooImpl)

应用接口值的理论类型来断言。

总的来说,go vet 的 ifaceassert 用于查看接口类型断言是否无效, 防止因为有效类型断言而导致的 bug。

ifaceassert 是 go vet 提供的另一个性能, 用于检测接口断言是否正确。

接口断言的格局是:

obj.(T)

这里 obj 必须实现接口 T, 否则会 panic。

举个例子:

type I interface {M() 
}

type T struct {}

func (t T) M() {}

func foo(i I) {t := i.(T) // 这里可能 panic!
    t.M()}

这里咱们对 i 执行接口断言, 假如 i 可能是不同类型的对象, 那么 i.(T) 可能就会 panic。

go vet 能够检测到这种状况:

./main.go:11: assertion `i.(T)` used in non-type assertion context, advisable to check type first   
         t := i.(T)  
                 ^  

它倡议咱们先查看 i 的类型, 而后再执行接口断言:

t, ok := i.(T)
if ok {t.M() 
}

应用 ok 判断变量是否具备该类型, 再执行接口断言。

所以,ifaceassert 能帮忙咱们查看接口断言是否正当, 防止因为谬误的接口断言而导致的 panic。


21. inspect (不算分析器)

optimize AST traversal for later passes

inspect 包 定义了一个分析器,它为包的语法树提供 AST 查看器 (golang.org/x/tools/go/ast/inspector.Inspector)。它只是其余分析器的构建块。另一种剖析中的应用示例:

package xxxxx

import (
    "go/ast"

    "golang.org/x/tools/go/analysis"
    "golang.org/x/tools/go/analysis/passes/inspect"
    "golang.org/x/tools/go/ast/inspector"
)

var Analyzer = &analysis.Analyzer{
    ...
    Requires:       []*analysis.Analyzer{inspect.Analyzer},
}

func run(pass *analysis.Pass) (interface{}, error) {inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
    inspect.Preorder(nil, func(n ast.Node) {//...})
    return nil, nil
}


22. internal(不算分析器)

Package analysisutil defines various helper functions used by two or more packages beneath go/analysis.

Analysisutil 包定义了 go/analysis 下的两个或多个包应用的各种辅助函数。

即一些专用的辅助函数


23. loopclosure

check references to loop variables from within nested functions

查看嵌套函数内对循环变量的援用此分析器报告函数文字援用关闭循环的迭代变量的地位,并且循环以这样的形式(例如应用 go 或 defer)调用该函数,该形式可能比循环迭代寿命更长,并且可能察看到谬误的变量值。

在此示例中,所有提早函数在循环实现后运行,因而所有函数都会察看 v 的最终值。

 for _, v := range list {defer func() {use(v) // incorrect
        }()}

一种解决办法是为循环的每次迭代创立一个新变量:

 for _, v := range list {
        v := v // new var per iteration
        defer func() {use(v) // ok
        }()}

下一个示例应用 go 语句并有相似的问题。此外,它还存在数据竞争,因为循环更新 v 与拜访它的 goroutine 并发。

for _, v := range elem {go func() {use(v)  // incorrect, and a data race
        }()}

修复与之前雷同。查看器还报告由 golang.org/x/sync/errgroup.Group 启动的 goroutine 中的问题。这种模式的一个难以发现的变体在并行测试中很常见:

func Test(t *testing.T) {
        for _, test := range tests {t.Run(test.name, func(t *testing.T) {t.Parallel()
                use(test) // incorrect, and a data race
            })
        }
    }

t.Parallel() 调用导致函数的其余部分与循环同时执行。

分析器仅在最初一个语句中报告援用,因为它不够深刻,无奈了解可能使援用良性的后续语句的影响。(“最初一条语句”在 if、switch 和 select 等复合语句中递归定义。)

请参阅:https://golang.org/doc/go_faq.html#closures_and_goroutines

以下供参考:

loopclosure 是 go vet 提供的一个性能, 用于检测 for 循环内定义的函数是否援用了循环变量。

举个例子:

func main() {
    for i := 0; i < 5; i++ {go func() {fmt.Println(i)  // 这里援用了循环变量 i
        }()}
}

这里咱们在 for 循环中定义了一个匿名函数, 该函数援用了循环变量 i。

因为 go 是通过复制变量来传入函数的参数, 所以循环完结后, 所有的函数都会援用同一个 i 变量的值(5)。

go vet 能够检测到这个 Situation:

./main.go:4: i captured by func literal
            fmt.Println(i)   
                       ^  

它通知咱们 func literal(匿名函数)捕捉到了循环变量 i。

正确的写法应该是:

for i := 0; i < 5; i++ {
   i := i  
   go func() {fmt.Println(i)
   }()}

应用 i := i 从新定义 i 变量, 这样每个匿名函数都会援用本人的 i 变量值。

所以总的来说, loopclosure 能够帮忙咱们查看 for 循环中的匿名函数是否正确援用了循环变量, 防止常见的闭包谬误。


24. lostcancel

check cancel func returned by context.WithCancel is called

The cancellation function returned by context.WithCancel, WithTimeout, and WithDeadline must be called or the new context will remain live until its parent context is cancelled. (The background context is never cancelled.)

必须调用 context.WithCancel、WithTimeout 和 WithDeadline 返回的勾销函数,否则新上下文将放弃活动状态,直到其父上下文被勾销。(后盾上下文永远不会被勾销。)

这段文本是对于 Go 语言中应用 context 包创立上下文的函数 context.WithCancelcontext.WithTimeoutcontext.WithDeadline 的应用阐明。

在 Go 语言中,context 包提供了一种用于在多个 Goroutine 之间传递勾销信号和截止工夫的机制,以便在适合的时候勾销或超时某个操作。

这段文本中提到的内容是指:当应用 context.WithCancelcontext.WithTimeoutcontext.WithDeadline 函数创立一个新的上下文时,会返回一个勾销函数(cancel function)。这个勾销函数能够用来勾销上下文,即进行所有应用该上下文派生进去的 Goroutine。

然而,如果你创立了一个新的上下文(应用上述函数之一)但没有调用返回的勾销函数,那么这个新的上下文将始终处于活动状态,不会主动勾销。这意味着其中的 Goroutine 将不会被开释,会继续执行。这可能导致资源透露或程序逻辑谬误。

须要留神的是,背景上下文(background context)是一个非凡的上下文,它永远不会被勾销,因为它是所有上下文的根节点。在应用 context.Background() 创立背景上下文时,不须要放心未调用勾销函数的问题,因为它自身永远不会被勾销。

所以,如果你在代码中应用了 context.WithCancelcontext.WithTimeoutcontext.WithDeadline 创立了新的上下文,请确保在不再须要该上下文时及时调用返回的勾销函数,以便及时开释相干资源并进行相干 Goroutine 的执行。

package main

import (
    "context"
    "time"
)

func main() {ctx, _ := context.WithTimeout(context.Background(), 1*time.Second)

    go func() {// 遗记调用 cancel, 导致 context 透露}()

    _ = ctx

    time.Sleep(2 * time.Second)
}

lostcancel 能够帮忙咱们查看是否正确地调用了 context 的 cancel 函数, 防止 context 透露问题。


25. nilfunc

check for useless comparisons between functions and nil

一种无用的比拟是相似 f == nil 而不是 f() == nil 的比拟。

package main

func main() {

    if shuang == nil {print(123)
    }
}

func shuang() {print(678)
}


26. nilness(未集成)

check for redundant or impossible nil comparisons

查看冗余或不可能的零比拟

包 nilness 查看 SSA 函数的控制流图并报告谬误,例如 nil 指针勾销援用和进化 nil 指针比拟。

nilness 查看器查看包中每个函数的控制流图,并报告 nil 指针勾销援用、进化 nil 指针以及 nil 值的恐慌。简并比拟的模式为 x==nil 或 x!=nil,其中 x 动态地已知为 nil 或非 nil。这些经常是谬误,特地是与控制流相干的谬误。查看带有 nil 值的恐慌,因为它们无奈被检测到

相干 case 参考: https://github.com/golang/tools/blob/master/go/analysis/passes/nilness/testdata/src/a/a.go

2023 年新增


27. pkgfact(未集成)

gather name/value pairs from constant declarations

从常量申明中收集 name/value 对

pkgfact 包是 包事实机制 (package fact mechanism) 的演示和测试。pkgfact 剖析的输入是一组从剖析的包及其导入的依赖项中收集的键 / 值对。每个键 / 值对都来自一个顶级常量申明,其名称以“_”结尾和结尾。例如:

package p

const _greeting_  = "hello"
const _audience_  = "world"

包 p 的 pkgfact 剖析输入将是:

{"greeting": "hello", "audience": "world"}.

In addition, the analysis reports a diagnostic at each import showing which key/value pairs it contributes.

package fact mechanism 是什么?

Package fact mechanism 是 Go 语言的一种机制, 它能够在编译时收集包的信息, 并且这些信息能够在运行时被拜访。

Go 收集的两种 fact 信息是:

  1. Package facts: 包级别的信息。包含包的门路、名字、导入门路等。
  2. Type facts: 类型级别的信息。包含类型的大小、内置办法等。

这些 fact 信息会被记录在一个叫.a 的文件中, 这个文件会随代码一起编译。而后在运行时, 程序能够通过 reflection 拜访这些信息。

举个例子, 要获取一个包的名称, 能够这样做:

import (
    "reflect"
    "runtime"
)

func main() {pname :=  runtime.FuncForPC(reflect.ValueOf(main).Pointer()).Name() 
    parts := strings.Split(pname, ".")
    fmt.Println(parts[len(parts)-1])  // prints "main"
}

这里应用 reflect 获取 main 函数的指针, 而后通过 runtime 获取函数名称。这个名称蕴含了包名, 因而咱们能够提取出包名。

Package fact mechanism 让程序能够在运行时获取编译时已知的信息。比方包名、导入门路等。

总的来说:

  • Go 在编译时收集包级别和类型级别的信息
  • 这些信息贮存在.a 文件中
  • 程序能够在运行时通过 reflection 拜访这些信息
  • Package facts mechanism 让程序能够获取编译时已知的元信息

以下内容供参考, 未必精确:

pkgfact 是一个 go vet 提供的性能, 它用于查看包级别的 fact 信息。包含:

  • 包是否被导入但未应用
  • 多个包是否援用同一个导入门路

咱们来看个例子:

import (
    "fmt"  
    "math"  // 这个包未应用  
)

func main() {fmt.Println("hello")
}

这里咱们导入了 math 包然而未应用,go vet 能够查看到:

./main.go:3: import of package "math" is unused  
       "math"  
           ^^^  

它提醒 math 包被导入但未应用。

另一个例子:

import (
    "fmt"   
    "encoding/json"
)

import . "morejson" // 应用了雷同的导入门路

这里同一个导入门路 ”json” 被多个包导入,go vet 能够检测到:

./main.go:6: import redefinition:
        encoding/json previously imported at ./main.go:3
        morejson imported here

它提醒有 import redefinition。

通过查看包的 fact 信息,pkgfact 能够帮忙咱们:

  • 检测包是否被导入但未应用
  • 检测 import 是否存在 redefinition
  • 防止因而产生一些潜在的 bug

总的来说: pkgfact 用于查看包级别的 fact 信息, 以放弃 imports 的正确性。它会查看:

  • 包是否被导入但未应用
  • 是否有 import redefinition 的状况


28. printf

check consistency of Printf format strings and arguments

查看 Printf 格局字符串和参数的一致性

package main

import "fmt"

func main() {fmt.Printf("%d %s", 1) // ./main.go:7:2: fmt.Printf format %s reads arg #2, but call has 1 arg

    fmt.Printf("%s", 1) // ./main.go:9:2: fmt.Printf format %s has arg 1 of wrong type int

}


29. reflectvaluecompare(未集成)

check for comparing reflect.Value values with == or reflect.DeepEqual

查看将 reflect.Value 值与 == 或 reflect.DeepEqual 进行比拟

ReflectValueCompare 查看器查找以下模式的表达式:

    v1 == v2
    v1 != v2
    reflect.DeepEqual(v1, v2)

其中 v1 或 v2 是 Reflect.Values。间接比拟 reflect.Values 简直必定是不正确的,因为它比拟的是 reflect 包的外部示意,而不是底层值。可能的目标是:

    v1.Interface() == v2.Interface()
    v1.Interface() != v2.Interface()
    reflect.DeepEqual(v1.Interface(), v2.Interface())

相干 case 参考: https://github.com/golang/tools/blob/master/go/analysis/passes/reflectvaluecompare/testdata/src/a/a.go


30. shadow(未集成)

check for possible unintended shadowing of variables

查看变量可能呈现的意外暗影

该分析器查看暗藏变量。暗藏变量是在外部作用域中申明的变量,其名称和类型与内部作用域中的变量雷同,并且在申明外部变量之后提及内部变量。

(这个定义能够细化;该模块产生太多误报,并且默认状况下尚未启用。)

例如:

func BadRead(f *os.File, buf []byte) error {
        var err error
        for {n, err := f.Read(buf) // shadows the function variable 'err'
            if err != nil {break // causes return of wrong value}
            foo(buf)
        }
        return err
    }


31. shift

check for shifts that equal or exceed the width of the integer

查看是否存在等于或超过整数宽度的移位

package shift

import "unsafe"

func ShiftTest() {
    var i8 int8
    _ = i8 << 7
    _ = (i8 + 1) << 8 // want ".i8 . 1. .8 bits. too small for shift of 8"
    _ = i8 << (7 + 1) // want "i8 .8 bits. too small for shift of 8"
    _ = i8 >> 8       // want "i8 .8 bits. too small for shift of 8"
    i8 <<= 8          // want "i8 .8 bits. too small for shift of 8"
    i8 >>= 8          // want "i8 .8 bits. too small for shift of 8"
    var i16 int16
    _ = i16 << 15
    _ = i16 << 16 // want "i16 .16 bits. too small for shift of 16"
    _ = i16 >> 16 // want "i16 .16 bits. too small for shift of 16"
    i16 <<= 16    // want "i16 .16 bits. too small for shift of 16"
    i16 >>= 16    // want "i16 .16 bits. too small for shift of 16"
    var i32 int32
    _ = i32 << 31
    _ = i32 << 32 // want "i32 .32 bits. too small for shift of 32"
    _ = i32 >> 32 // want "i32 .32 bits. too small for shift of 32"
    i32 <<= 32    // want "i32 .32 bits. too small for shift of 32"
    i32 >>= 32    // want "i32 .32 bits. too small for shift of 32"
    var i64 int64
    _ = i64 << 63
    _ = i64 << 64 // want "i64 .64 bits. too small for shift of 64"
    _ = i64 >> 64 // want "i64 .64 bits. too small for shift of 64"
    i64 <<= 64    // want "i64 .64 bits. too small for shift of 64"
    i64 >>= 64    // want "i64 .64 bits. too small for shift of 64"
    var u8 uint8
    _ = u8 << 7
    _ = u8 << 8 // want "u8 .8 bits. too small for shift of 8"
    _ = u8 >> 8 // want "u8 .8 bits. too small for shift of 8"
    u8 <<= 8    // want "u8 .8 bits. too small for shift of 8"
    u8 >>= 8    // want "u8 .8 bits. too small for shift of 8"
    var u16 uint16
    _ = u16 << 15
    _ = u16 << 16 // want "u16 .16 bits. too small for shift of 16"
    _ = u16 >> 16 // want "u16 .16 bits. too small for shift of 16"
    u16 <<= 16    // want "u16 .16 bits. too small for shift of 16"
    u16 >>= 16    // want "u16 .16 bits. too small for shift of 16"
    var u32 uint32
    _ = u32 << 31
    _ = u32 << 32 // want "u32 .32 bits. too small for shift of 32"
    _ = u32 >> 32 // want "u32 .32 bits. too small for shift of 32"
    u32 <<= 32    // want "u32 .32 bits. too small for shift of 32"
    u32 >>= 32    // want "u32 .32 bits. too small for shift of 32"
    var u64 uint64
    _ = u64 << 63
    _ = u64 << 64  // want "u64 .64 bits. too small for shift of 64"
    _ = u64 >> 64  // want "u64 .64 bits. too small for shift of 64"
    u64 <<= 64     // want "u64 .64 bits. too small for shift of 64"
    u64 >>= 64     // want "u64 .64 bits. too small for shift of 64"
    _ = u64 << u64 // Non-constant shifts should succeed.

    var i int
    _ = i << 31
    const in = 8 * unsafe.Sizeof(i)
    _ = i << in // want "too small for shift"
    _ = i >> in // want "too small for shift"
    i <<= in    // want "too small for shift"
    i >>= in    // want "too small for shift"
    const ix = 8*unsafe.Sizeof(i) - 1
    _ = i << ix
    _ = i >> ix
    i <<= ix
    i >>= ix

    var u uint
    _ = u << 31
    const un = 8 * unsafe.Sizeof(u)
    _ = u << un // want "too small for shift"
    _ = u >> un // want "too small for shift"
    u <<= un    // want "too small for shift"
    u >>= un    // want "too small for shift"
    const ux = 8*unsafe.Sizeof(u) - 1
    _ = u << ux
    _ = u >> ux
    u <<= ux
    u >>= ux

    var p uintptr
    _ = p << 31
    const pn = 8 * unsafe.Sizeof(p)
    _ = p << pn // want "too small for shift"
    _ = p >> pn // want "too small for shift"
    p <<= pn    // want "too small for shift"
    p >>= pn    // want "too small for shift"
    const px = 8*unsafe.Sizeof(p) - 1
    _ = p << px
    _ = p >> px
    p <<= px
    p >>= px

    const oneIf64Bit = ^uint(0) >> 63 // allow large shifts of constants; they are used for 32/64 bit compatibility tricks

    var h uintptr
    h = h<<8 | (h >> (8 * (unsafe.Sizeof(h) - 1)))
    h <<= 8 * unsafe.Sizeof(h) // want "too small for shift"
    h >>= 7 * unsafe.Alignof(h)
    h >>= 8 * unsafe.Alignof(h) // want "too small for shift"
}

执行 go vet main.go 后输入:

# command-line-arguments
./main.go:8:6: (i8 + 1) (8 bits) too small for shift of 8
./main.go:9:6: i8 (8 bits) too small for shift of 8
./main.go:10:6: i8 (8 bits) too small for shift of 8
./main.go:11:2: i8 (8 bits) too small for shift of 8
./main.go:12:2: i8 (8 bits) too small for shift of 8
./main.go:15:6: i16 (16 bits) too small for shift of 16
./main.go:16:6: i16 (16 bits) too small for shift of 16
./main.go:17:2: i16 (16 bits) too small for shift of 16
./main.go:18:2: i16 (16 bits) too small for shift of 16
./main.go:21:6: i32 (32 bits) too small for shift of 32
./main.go:22:6: i32 (32 bits) too small for shift of 32
./main.go:23:2: i32 (32 bits) too small for shift of 32
./main.go:24:2: i32 (32 bits) too small for shift of 32
./main.go:27:6: i64 (64 bits) too small for shift of 64
./main.go:28:6: i64 (64 bits) too small for shift of 64
./main.go:29:2: i64 (64 bits) too small for shift of 64
./main.go:30:2: i64 (64 bits) too small for shift of 64
./main.go:33:6: u8 (8 bits) too small for shift of 8
./main.go:34:6: u8 (8 bits) too small for shift of 8
./main.go:35:2: u8 (8 bits) too small for shift of 8
./main.go:36:2: u8 (8 bits) too small for shift of 8
./main.go:39:6: u16 (16 bits) too small for shift of 16
./main.go:40:6: u16 (16 bits) too small for shift of 16
./main.go:41:2: u16 (16 bits) too small for shift of 16
./main.go:42:2: u16 (16 bits) too small for shift of 16
./main.go:45:6: u32 (32 bits) too small for shift of 32
./main.go:46:6: u32 (32 bits) too small for shift of 32
./main.go:47:2: u32 (32 bits) too small for shift of 32
./main.go:48:2: u32 (32 bits) too small for shift of 32
./main.go:51:6: u64 (64 bits) too small for shift of 64
./main.go:52:6: u64 (64 bits) too small for shift of 64
./main.go:53:2: u64 (64 bits) too small for shift of 64
./main.go:54:2: u64 (64 bits) too small for shift of 64
./main.go:60:6: i (64 bits) too small for shift of 64
./main.go:61:6: i (64 bits) too small for shift of 64
./main.go:62:2: i (64 bits) too small for shift of 64
./main.go:63:2: i (64 bits) too small for shift of 64
./main.go:73:6: u (64 bits) too small for shift of 64
./main.go:74:6: u (64 bits) too small for shift of 64
./main.go:75:2: u (64 bits) too small for shift of 64
./main.go:76:2: u (64 bits) too small for shift of 64
./main.go:86:6: p (64 bits) too small for shift of 64
./main.go:87:6: p (64 bits) too small for shift of 64
./main.go:88:2: p (64 bits) too small for shift of 64
./main.go:89:2: p (64 bits) too small for shift of 64
./main.go:100:2: h (64 bits) too small for shift of 64
./main.go:102:2: h (64 bits) too small for shift of 64

以下内容供参考:

shift 是 go vet 提供的一个性能, 它用于查看移位操作是否正确。

在 Go 语言中, 不同类型的数值 shifting 是不一样的。

  • uint 类型承受无符号移位
  • int 类型承受有符号移位

举个例子:

var a uint = 1
a << 2 // 4

var b int = 1
b << 2 // -8

对 uint 做左移是无符号的, 后果是 4。
而对 int 做左移是有符号的, 后果是 -8。

go vet 能够检测到这种混用:

./main.go:4: result of left shift of int by uint will be uint   
     b << 2  
         ^^

它提醒左移的后果将是 uint 类型。

为了防止混用不同类型的移位操作, 咱们应该把它们转换为雷同的类型:

b << uint(2)  // 强制转换为 uint 类型

所以,shift 性能次要用于查看:

  • int 和 uint 之间的移位混用
  • 是否应用正确的类型转换

以防止由此产生的 bug。

总的来说:

  • int 和 uint 的移位后果不同
  • shift 能够查看 int 和 uint 之间是否存在移位混用
  • 通过提醒增加类型转换, 能够防止潜在的 bug


32. sigchanyzer

check for unbuffered channel of os.Signal

查看 os.Signal 的无缓冲通道

该查看器报告这种模式的调用表达式

signal.Notify(c <-chan os.Signal, sig ...os.Signal)

其中 c 是无缓冲通道,可能存在失落信号的危险。

package sigchanyzer

import (
    "os"
    "os/signal"
)

func g() {c := make(chan os.Signal)
    signal.Notify(c, os.Interrupt) // want "misuse of unbuffered os.Signal channel as argument to signal.Notify"
    _ = <-c
}

执行 go vet main.go 后输入:

# command-line-arguments
./main.go:10:2: misuse of unbuffered os.Signal channel as argument to signal.Notify

更多 case,参考: https://github.com/golang/tools/blob/master/go/analysis/passes/sigchanyzer/testdata/src/a/a.go

以下内容供参考:

sigchanyzer 是 go vet 提供的一个性能, 它用于查看信号处理是否正确。

在 Go 语言中, 咱们应用 signal 包来解决 OS 信号, 像 SIGINT、SIGTERM 等。

举个例子, 监听 SIGINT 信号:

signal.Notify(c, os.Interrupt)

for {
    select {
    case <-c:
        // 解决 SIGINT 信号         
    } 
}

这里咱们应用 signal.Notify 注册了 SIGINT 信号, 而后不停查看 channel 是否有信号。

go vet 能够查看咱们是否正确处理了信号:

signal.Notify(c, os.Interrupt)

<-c // 谬误! 循环只查看一次 channel

这里咱们只查看一次 channel, 没有正确处理 SIGINT 信号。

go vet 能够检测到:

./main.go:5: ignoring subsequent SIGINT after first  
     <-c
            ^  

所以 sigchanyzer 次要能够查看是否:

  • 正确应用 select 监听信号 channel
  • 在循环中屡次查看信号 channel

以确保全副信号都被解决。

通过 go vet, 咱们能够防止 accidentally ignoring OS signals 的谬误。

总的来说,sigchanyzer 用来查看信号处理是否正确, 包含:

  • 应用 select 机制监听信号
  • 在循环中屡次查看信号 channel
  • 防止疏忽信号

以确保咱们的代码能正确处理 OS 信号。


33. slog

check for invalid structured logging calls

slog 查看器从 log/slog 包中查找采纳交替键值对的函数调用。它报告键地位中的参数既不是字符串也不是 slog.Attr 且最终键短少其值的调用。

例如,它会报告

slog.Warn("message", 11, "k") // slog.Warn arg "11" should be a string or a slog.Attr

slog.Info("message", "k1", v1, "k2") // call to slog.Info missing a final value

更多 case,参考: https://github.com/golang/tools/blob/master/go/analysis/passes/slog/testdata/src/a/a.go

2023 年新增


34. sortslice(未集成)

check the argument type of sort.Slice

sort.Slice 须要切片类型的参数。检查一下传递给 sort.Slice 的 interface{} 值实际上是一个切片

package main

import "sort"

func main() {

    i := 5
    sortFn := func(i, j int) bool {return false}
    sort.Slice(i, sortFn)         // want "sort.Slice's argument must be a slice; is called with int"sort.SliceStable(i, sortFn)   // want"sort.SliceStable's argument must be a slice; is called with int"
    sort.SliceIsSorted(i, sortFn) // want "sort.SliceIsSorted's argument must be a slice; is called with int"
}

执行 go vet main.go 后未失效,这是因为 tools 我的项目中提供了,然而 go 我的项目中未集成进来

更多 case,参考: https://github.com/golang/tools/blob/master/go/analysis/passes/sortslice/testdata/src/a/a.go

以后 go vet 中集成进来的分析器,见 https://github.com/golang/go/blob/master/src/cmd/vet/main.go#L47

能够钻研下为什么没有集成进去,是不是忘了..

看起来不是,https://github.com/golang/go/tree/master/src/cmd/vet 这里提到 Over time many checks have been added to vet’s suite, but many more have been rejected as not appropriate for the tool.


35. stdmethods

checks for misspellings in the signatures of methods similar to well-known interfaces

查看相似于家喻户晓的接口的办法签名中的拼写错误。

有时,类型可能旨在满足接口,但可能因为其办法签名中的谬误而无奈满足接口的要求。

例如,这个 WriteTo 办法的后果应该是 (int64, error),而不是 error,以满足 io.WriterTo:

 type myWriterTo struct{...}
 func (myWriterTo) WriteTo(w io.Writer) error {...}

此查看可确保名称与规范库中几个家喻户晓的接口办法之一匹配的每个办法都具备该接口的正确签名。查看的办法名称包含:

  • Format GobEncode GobDecode MarshalJSON MarshalXML
  • Peek ReadByte ReadFrom ReadRune Scan Seek
  • UnmarshalJSON UnreadByte UnreadRune WriteByte WriteTo

更多 case,参考 https://github.com/golang/tools/blob/master/go/analysis/passes/stdmethods/testdata/src/a/a.go


36. stringintconv

check for string(int) conversions

此查看器标记 string(x) 模式的转换,其中 x 是整数(但不是字节 byte 或符文 rune)类型。不激励进行此类转换,因为它们返回 Unicode 代码点 x 的 UTF-8 示意模式,而不是人们所冀望的 x 的十进制字符串示意模式。此外,如果 x 示意有效代码点,则不能动态回绝转换。

对于打算应用代码点的转换,请思考将其替换为 string(rune(x))。否则,strconv.Itoa 及其等效项返回所需基数中值的字符串示意模式。

package stringintconv

type A string

type B = string

type C int

type D = uintptr

func StringTest() {
    var (
        i int
        j rune
        k byte
        l C
        m D
        n = []int{0, 1, 2}
        o struct{x int}
    )
    const p = 0
    _ = string(i) // want `^conversion from int to string yields a string of one rune, not a string of digits \(did you mean fmt\.Sprint\(x\)\?\)$`
    _ = string(j)
    _ = string(k)
    _ = string(p)    // want `^conversion from untyped int to string yields a string of one rune, not a string of digits \(did you mean fmt\.Sprint\(x\)\?\)$`
    _ = A(l)         // want `^conversion from C \(int\) to A \(string\) yields a string of one rune, not a string of digits \(did you mean fmt\.Sprint\(x\)\?\)$`
    _ = B(m)         // want `^conversion from uintptr to B \(string\) yields a string of one rune, not a string of digits \(did you mean fmt\.Sprint\(x\)\?\)$`
    _ = string(n[1]) // want `^conversion from int to string yields a string of one rune, not a string of digits \(did you mean fmt\.Sprint\(x\)\?\)$`
    _ = string(o.x)  // want `^conversion from int to string yields a string of one rune, not a string of digits \(did you mean fmt\.Sprint\(x\)\?\)$`
}

执行 go vet main.go,输入:

# command-line-arguments
./main.go:22:6: conversion from int to string yields a string of one rune, not a string of digits (did you mean fmt.Sprint(x)?)
./main.go:25:6: conversion from untyped int to string yields a string of one rune, not a string of digits (did you mean fmt.Sprint(x)?)
./main.go:26:6: conversion from C (int) to A (string) yields a string of one rune, not a string of digits (did you mean fmt.Sprint(x)?)
./main.go:27:6: conversion from uintptr to B (string) yields a string of one rune, not a string of digits (did you mean fmt.Sprint(x)?)
./main.go:28:6: conversion from int to string yields a string of one rune, not a string of digits (did you mean fmt.Sprint(x)?)
./main.go:29:6: conversion from int to string yields a string of one rune, not a string of digits (did you mean fmt.Sprint(x)?)


37. structtag

checks struct field tags are well formed

查看构造字段标签的格局是否正确

查看构造体字段标签是否合乎 reflect.StructTag.Get

还报告与未导出字段一起应用的某些构造标签(json、xml)

package structtag

type StructTagTest struct {
    A   int "hello"            // want "`hello` not compatible with reflect.StructTag.Get: bad syntax for struct tag pair"
    B   int "\tx:\"y\""// want"not compatible with reflect.StructTag.Get: bad syntax for struct tag key"C   int"x:\"y\"\tx:\"y\"" // want "not compatible with reflect.StructTag.Get"
    D   int "x:`y`"            // want "not compatible with reflect.StructTag.Get: bad syntax for struct tag value"
    E   int "ct\brl:\"char\""// want"not compatible with reflect.StructTag.Get: bad syntax for struct tag pair"F   int `:"emptykey"`      // want"not compatible with reflect.StructTag.Get: bad syntax for struct tag key"G   int `x:"noEndQuote`    // want "not compatible with reflect.StructTag.Get: bad syntax for struct tag value"
    H   int `x:"trunc\x0"`     // want "not compatible with reflect.StructTag.Get: bad syntax for struct tag value"
    I   int `x:"foo",y:"bar"`  // want "not compatible with reflect.StructTag.Get: key:.value. pairs not separated by spaces"
    J   int `x:"foo"y:"bar"`   // want "not compatible with reflect.StructTag.Get: key:.value. pairs not separated by spaces"
    OK0 int `x:"y" u:"v" w:""`
    OK1 int `x:"y:z" u:"v" w:""` // note multiple colons.
    OK2 int "k0:\"values contain spaces\"k1:\"literal\ttabs\"k2:\"and\\tescaped\\tabs\""OK3 int `under_scores:"and"CAPS:"ARE_OK"`
}

执行 go vet main.go 后输入:

# command-line-arguments
./main.go:4:2: struct field tag `hello` not compatible with reflect.StructTag.Get: bad syntax for struct tag pair
./main.go:5:2: struct field tag `       x:"y"` not compatible with reflect.StructTag.Get: bad syntax for struct tag key
./main.go:6:2: struct field tag `x:"y"  x:"y"` not compatible with reflect.StructTag.Get: key:"value" pairs not separated by spaces
./main.go:7:2: struct field tag "x:`y`" not compatible with reflect.StructTag.Get: bad syntax for struct tag value
./main.go:8:2: struct field tag "ct\brl:\"char\"" not compatible with reflect.StructTag.Get: bad syntax for struct tag pair
./main.go:9:2: struct field tag `:"emptykey"` not compatible with reflect.StructTag.Get: bad syntax for struct tag key
./main.go:10:2: struct field tag `x:"noEndQuote` not compatible with reflect.StructTag.Get: bad syntax for struct tag value
./main.go:11:2: struct field tag `x:"trunc\x0"` not compatible with reflect.StructTag.Get: bad syntax for struct tag value
./main.go:12:2: struct field tag `x:"foo",y:"bar"` not compatible with reflect.StructTag.Get: key:"value" pairs not separated by spaces
./main.go:13:2: struct field tag `x:"foo"y:"bar"` not compatible with reflect.StructTag.Get: key:"value" pairs not separated by spaces

更多 case,参考 https://github.com/golang/tools/blob/master/go/analysis/passes/structtag/testdata/src/a/a.go


38. testinggoroutine

report calls to (testing.T).Fatal from goroutines started by a test*

报告由测试启动的 goroutine 对 (*testing.T).Fatal 的调用

忽然终止测试的函数,例如 *testing.T 的 Fatal、Fatalf、FailNow 和 Skip{,f,Now} 办法,必须从测试 goroutine 自身调用。该查看器检测由测试启动的 goroutine 中产生的对这些函数的调用。例如:

func TestFoo(t *testing.T) {go func() {t.Fatal("oops") // error: (*T).Fatal called from non-test goroutine
    }()}

package testinggoroutine

import (
    "sync"
    "testing"
)

func TestBadFatalf(t *testing.T) {
    var wg sync.WaitGroup
    defer wg.Wait()

    for i := 0; i < 2; i++ {wg.Add(1)
        go func(id int) {defer wg.Done()
            t.Fatalf("TestFailed: id = %v\n", id) // want "call to .+T.+Fatalf from a non-test goroutine"
        }(i)
    }
}

更多 case,参考 https://github.com/golang/tools/blob/master/go/analysis/passes/testinggoroutine/testdata/src/a/a.go


39. tests

check for common mistaken usages of tests and examples

这个分析器 运行测试、基准、含糊测试和示例性能,查看格局谬误的名称、谬误的签名和记录不存在的标识符的示例。

请参阅 golang.org/pkg/testing 中的包测试文档,理解测试、基准和示例强制执行的约定。

这一块有不少 todo 能够去看看

相干 case,参考 https://github.com/golang/tools/blob/master/go/analysis/passes/tests/testdata/src/a/a_test.go


40. timeformat

check for calls of (time.Time).Format or time.Parse with 2006-02-01

查找格局为 2006-02-01 (yyyy-dd-mm) 的工夫格局。在国内上,“yyyy-dd-mm”不会呈现在通用日历日期规范中,因而更可能是 2006-01-02 (yyyy-mm-dd)

package timeformat

import "time"

func hasError() {a, _ := time.Parse("2006-02-01 15:04:05", "2021-01-01 00:00:00") // want `2006-02-01 should be 2006-01-02`
    a.Format(`2006-02-01`)                                           // want `2006-02-01 should be 2006-01-02`
    a.Format("2006-02-01 15:04:05")                                  // want `2006-02-01 should be 2006-01-02`

    const c = "2006-02-01"
    a.Format(c) // want `2006-02-01 should be 2006-01-02`
}

执行 go vet main.go 后输入:

# command-line-arguments
./main.go:6:22: 2006-02-01 should be 2006-01-02
./main.go:7:12: 2006-02-01 should be 2006-01-02
./main.go:8:12: 2006-02-01 should be 2006-01-02
./main.go:11:11: 2006-02-01 should be 2006-01-02

更多 case,参考 https://github.com/golang/tools/blob/master/go/analysis/passes/timeformat/testdata/src/a/a.go


41. unmarshal

report passing non-pointer or non-interface values to unmarshal

报告对 json.Unmarshal 等函数的调用,但其中参数类型不是指针或接口的状况。

更多 case,参考 https://github.com/golang/tools/blob/master/go/analysis/passes/unmarshal/testdata/src/a/a.go


42. unreachable

check for unreachable code

该分析器会查找执行永远无奈达到的语句,因为它们后面有 return 语句、对 panic 的调用、有限循环或相似的构造

package unreachable

func _() int {print(1)
    return 2
    println() // want "unreachable code"}

func _() int {
L:
    print(1)
    goto L
    println() // want "unreachable code"}

func _() int {print(1)
    panic(2)
    println() // want "unreachable code"}

输入:

# command-line-arguments
vet: ./main.go:7:1: missing return

更多 case,参考 https://github.com/golang/tools/blob/master/go/analysis/passes/unreachable/testdata/src/a/a.go


43. unsafeptr

check for invalid conversions of uintptr to unsafe.Pointer

查看 uintptr 到 unsafe.Pointer 的有效转换

报告可能谬误地应用 unsafe.Pointer 将整数转换为指针。如果从 uintptr 到 unsafe.Pointer 的转换意味着内存中存在一个保留指针值的 uintptr 类型的字,则该转换有效,因为该字对于堆栈复制和垃圾收集器来说是不可见的。

package unsafeptr

import "unsafe"

func f() {
    var x unsafe.Pointer
    var y uintptr
    x = unsafe.Pointer(y) // want "possible misuse of unsafe.Pointer"
    y = uintptr(x)

    // only allowed pointer arithmetic is ptr +/-/&^ num.
    // num+ptr is technically okay but still flagged: write ptr+num instead.
    x = unsafe.Pointer(uintptr(x) + 1)
    x = unsafe.Pointer(((uintptr((x))) + 1))
    x = unsafe.Pointer(1 + uintptr(x))          // want "possible misuse of unsafe.Pointer"
    x = unsafe.Pointer(uintptr(x) + uintptr(x)) // want "possible misuse of unsafe.Pointer"
}

更多 case,参考 https://github.com/golang/tools/blob/master/go/analysis/passes/unsafeptr/testdata/src/a/a.go


44. unusedresult

checks for unused results of calls to certain pure functions

有些函数(例如 fmt.Errorf)会返回后果并且没有副作用,因而抛弃后果始终是谬误的。其余函数可能会返回一个不能被疏忽的谬误,或者一个必须调用的清理操作。当调用后果被疏忽时,该分析器会报告对此类函数的调用。

能够应用标记来管制该组函数。

package unusedresult

import (
    "bytes"
    "errors"
    "fmt"
    . "fmt"
)

func _() {fmt.Errorf("") // want"result of fmt.Errorf call not used"_ = fmt.Errorf("")

    errors.New("") // want"result of errors.New call not used"err := errors.New("")
    err.Error() // want `result of \(error\).Error call not used`

    var buf bytes.Buffer
    buf.String() // want `result of \(\*bytes.Buffer\).String call not used`

    fmt.Sprint("")  // want"result of fmt.Sprint call not used"fmt.Sprintf("") // want "result of fmt.Sprintf call not used"

    Sprint("")  // want"result of fmt.Sprint call not used"Sprintf("") // want "result of fmt.Sprintf call not used"
}

输入:

# command-line-arguments
./main.go:11:12: result of fmt.Errorf call not used
./main.go:14:12: result of errors.New call not used
./main.go:17:11: result of (error).Error call not used
./main.go:20:12: result of (*bytes.Buffer).String call not used
./main.go:22:12: result of fmt.Sprint call not used
./main.go:23:13: result of fmt.Sprintf call not used
./main.go:25:8: result of fmt.Sprint call not used
./main.go:26:9: result of fmt.Sprintf call not used

相干 case,参考 https://github.com/golang/tools/blob/master/go/analysis/passes/unusedresult/testdata/src/a/a.go


45. unusedwrite(未集成)

checks for unused writes to the elements of a struct or array object

查看对构造或数组对象元素的未应用写入

报告从未读取的构造体字段和数组的写入实例。具体来说,当复制构造体对象或数组时,编译器会隐式复制其元素,并且写入此正本的任何元素都不会对原始对象执行任何操作。

例如:

type T struct {x int}

func f(input []T) {
    for i, v := range input {  // v is a copy
        v.x = i  // unused write to field x
    }
}

另一个例子是对于非指针接收者:

    type T struct {x int}

    func (t T) f() {  // t is a copy
        t.x = i  // unused write to field x
    }

更多 case,参考 https://github.com/golang/tools/blob/master/go/analysis/passes/unusedwrite/testdata/src/a/unusedwrite.go

tools 我的项目中提供了,然而 go 我的项目中未集成进来


46. usesgenerics(未集成)

checks for usage of generic features added in Go 1.18

查看 Go 1.18 中增加的泛型性能的应用状况

usegenerics 剖析报告包是否间接或间接应用与 Go 中泛型编程相干的某些性能。

相干 case 参考: https://github.com/golang/tools/tree/master/go/analysis/passes/usesgenerics/testdata/src

tools 我的项目中提供了,然而 go 我的项目中未集成进来


本文由 mdnice 多平台公布

正文完
 0