本文简要介绍go实现lint和golangci-lint使用。

what

linter为静态代码检查、分析工具,golang常见的有govet\golint\errcheck 等。通过工具其一,可以提前发现一些语法问题,比如变量作用域问题、数组下标越界、内存泄露等;其二可以根据团队规范定制lint规则,提升可读性,可维护性。

golang的linters比较多,比如 awesome-go-linters中 golint检查变量、函数名、注释等。errcheck为未检查错误等。golangci-lint是一个 Go linters 聚合器,通过配置来选择需要的linters。其特征如下:

  • ⚡非常快:并行运行linters,重用Go构建缓存和缓存分析结果。
  • ⚙️基于yaml的配置
  • 🖥集成VS Code, Sublime Text, GoLand, GNU Emacs, Vim, Atom, GitHub动作。
  • 🥇包含了很多linters,不需要安装它们。
  • 📈由于调优的默认设置导致的最小误报数。
  • 🔥漂亮的输出颜色,源代码行和标记的标识符。

install

mac

macOS你可以使用brew在macOS上安装二进制版本:

brew install golangci-lint
brew upgrade golangci-lint

Install from Source

源码安装:

> go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.50.1

查看安装是否成功:

>golangci-lint --version
>golangci-lint has version v1.50.1 built from (unknown, mod sum: "h1:C829clMcZXEORakZlwpk7M4iDw2XiwxxKaG504SZ9zY=") on (unknown)

how

GolangCI-Lint 可以零配置使用。默认情况下启用以下 linters

>golangci-lint help linters
>Enabled by default linters:
errcheck: Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases [fast: false, auto-fix: false]
gosimple (megacheck): Linter for Go source code that specializes in simplifying code [fast: false, auto-fix: false]
govet (vet, vetshadow): Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string [fast: false, auto-fix: false]
ineffassign: Detects when assignments to existing variables are not used [fast: true, auto-fix: false]
staticcheck (megacheck): It's a set of rules from staticcheck. It's not the same thing as the staticcheck binary. The author of staticcheck doesn't support or approve the use of staticcheck as a library inside golangci-lint. [fast: false, auto-fix: false]
typecheck: Like the front-end of a Go compiler, parses and type-checks Go code [fast: false, auto-fix: false]
unused (megacheck): Checks Go code for unused constants, variables, functions and types [fast: false, auto-fix: false]

如何执行golangci-lint呢?在需要执行的项目目录下:

golangci-lint run

这相当于执行

golangci-lint run ./...

您可以选择要分析的目录和文件:

golangci-lint run dir1 dir2/... dir3/file1.go

接着,我们创建一个Example代码:linter_example.go

package main

import "fmt"

type People struct {
	Name string
}

func (p *People) String() string {
	return fmt.Sprintf("print: %v", p)
}

func main() {
	p := &People{}
	p.String()
}


执行lint,如果没有相关的配置文件,会走默认的lint配置

> golangci-lint run
level=warning msg="[runner] The linter 'golint' is deprecated (since v1.41.0) due to: The repository of the linter has been archived b
y the owner.  Replaced by revive."
linter_example.go:5:6: exported type `People` should have comment or be unexported (golint)
type People struct {
     ^
linter_example.go:10:9: printf: fmt.Sprintf format %v with arg p causes recursive (*demos/linter-demo.People).String method call (gove
t)
        return fmt.Sprintf("print: %v", p)
               ^
linter_example.go:15:10: unusedresult: result of (*demos/linter-demo.People).String call not used (govet)
        p.String()
                ^

我们可以根据lint提示修改

 printf: fmt。Sprintf格式%v与arg p导致递归( demos/ lininter -demo. people)。字符串方法调用(govet)。

在使⽤  fmt 包中的打印⽅法时,如果类型实现了这个接⼝,会直接调⽤。⽽中打印  p 的时候会直接调⽤  p 实现的  String() ⽅法,然后就产⽣了循环调⽤。

Custom Configuration

GolangCI-Lint 通过当前工作目录的以下路径中增加配置文件:

  • .golangci.yml
  • .golangci.yaml
  • .golangci.toml
  • .golangci.json

来实现自定义linters

例如我们添加了.golangci.yml

run:
  timeout: 5m
  modules-download-mode: readonly

linters:
  disable-all: true
  enable: # 下面是开启的lint列表
    - errcheck
    - goimports
    - golint
   # - govet 为了测试是否生效,关闭
    - staticcheck

linters-settings:
  golint:
    # minimal confidence for issues, default is 0.8
    min-confidence: 0.8

issues:
  exclude-use-default: false
  max-issues-per-linter: 0
  max-same-issues: 0

这里我们把govet 关闭了,在执行run

golangci-lint run
level=warning msg="[runner] The linter 'golint' is deprecated (since v1.41.0) due to: The repository of the linter has been archived b
y the owner.  Replaced by revive."
linter_example.go:5:6: exported type `People` should have comment or be unexported (golint)
type People struct {
     ^

可见关闭govet生效了。

reference