Go中linting的知识介绍、配置设置及替代包介绍

1,211 阅读6分钟

使用linters可以在执行前突出问题,从而提高可读性,并且有助于你的代码库的标准化。一个好的linter有配置设置,有助于减少对你不关心的规则的警告,使代码更容易理解、修改和维护。

在这篇文章中,我们将通过这些主题来了解更多关于linting的知识:

多年来,golint一直是Go中使用最广泛的linter。不幸的是,它现在已经被官方弃用并归档。golint的问题在于它不提供任何配置选项,总是应用所有的规则,这导致你不关心的规则出现警告。在这篇文章中,我们将使用revive包,以及探索其他go linting包。

相反,revive是一个快速的、可配置的、可扩展的、适应性强的、漂亮的Go的linter。它可以作为golint的替代品。

以下是revive与golint的不同之处:

  • 允许我们使用一个配置文件来启用或禁用规则
  • 允许我们用一个TOML文件来配置提示规则
  • 在运行相同的规则时,速度是golint的2倍
  • 提供了为一个文件或一系列行禁用特定规则或整个林特的功能(golint只允许对生成的文件这样做)。
  • 可选的类型检查。golint 中的大多数规则都不需要类型检查。如果你在配置文件中禁用它们,revive的运行速度将比golint快六倍以上。
  • 提供多种格式,让我们自定义输出结果
  • 允许我们为整个interter定制返回代码,或者只根据某些规则的失败来定制。
  • 每个人都可以通过自定义规则或格式化器轻松地扩展它
  • 与golint相比,revive提供了更多的规则。

用revive建立一个项目

打开一个终端并创建一个项目文件夹。导航到项目文件夹并运行以下命令来启动一个新的项目。

go mod init project

导航到你的Go项目,运行以下命令来安装revive linter包。

go install github.com/mgechev/revive@latest

创建一个main.go 文件,并在main.go 文件中添加以下代码片段。

package main
import (
    "fmt"
)
func main() {
    PrintName("Emmanuel")
    PrintAge(23)
}
func PrintName(name string) {
    fmt.Println(name)
}
func PrintAge(age int) {
    fmt.Println(age)
}

现在,在项目终端运行revive 命令,你应该得到以下报告。

main.go:11:1: exported function PrintName should have comment or be unexported
main.go:15:1: exported function PrintAge should have comment or be unexported

在Go中,导出的函数的第一个字母通常是大写的。一个有正确文档的代码库需要对导出的函数进行注释,并简要介绍该函数的用途,以便每个人都能理解它的作用。现在我们可以看到revive包是如何帮助我们写出具有良好文档的代码的。

现在,让我们给这些函数添加一些注释。

...
// This function uses the fmt.Println function to print a string.
func PrintName(name string) {
    fmt.Println(name)
}
// This function uses the fmt.Println function to print a number.
func PrintAge(age int) {
    fmt.Println(age)
}

执行revive命令,你应该有如下报告。

main.go:12:1: comment on exported function PrintName should 
be of the form "PrintName ..."
main.go:17:1: comment on exported function PrintAge should be of the form "PrintAge ..." 

Revive告诉我们,我们的注释应该以我们导出的函数的名称开始,以获得一个正确的文档化的代码库。

让我们把我们的注释改为以下内容。

...
// PrintName uses the fmt.Println function to print a string.
func PrintName(name string) {
    fmt.Println(name)
}
// PrintAge uses the fmt.Println function to print a number.
func PrintAge(age int) {
    fmt.Println(age)
}

有了这个,执行revive命令,你应该没有报告。

用revive抑制提示性错误

有时,有必要禁止在文件或包中出现的特定品评问题。配置文件中的注释和排除规则都可以用来实现这一目的。让我们依次来看看每种策略。

当你想禁用某一段代码的警告,但仍想将规则应用于项目的其他部分时,注释策略就很方便了。

下面是如何使用注释来禁止特定的提示问题。

package main
import (
    "fmt"
)
func main() {
    PrintName("Emmanuel")
}
// revive:disable:exported
func PrintName(name string) {
    fmt.Println(name)
}

其语法是:revive ,后面是冒号,然后是disable 。如果需要的话,再加一个冒号,然后是林特规则的名称。

为linters设置配置

这是revive linter包的一个了不起的功能,它解决了流行的golint linter包的主要挑战。

让我们看看如何配置revive linter包来禁用一些linting规则,以减少不必要的警告。

在项目文件夹中添加一个名为revive.toml 的文件,默认为 [revive](https://github.com/mgechev/revive#recommended-configuration)配置

ignoreGeneratedHeader = false
severity = "warning"
confidence = 0.8
errorCode = 0
warningCode = 0

[rule.blank-imports]
[rule.context-as-argument]
[rule.context-keys-type]
[rule.dot-imports]
[rule.error-return]
[rule.error-strings]
[rule.error-naming]
[rule.exported]
[rule.if-return]
[rule.increment-decrement]
[rule.var-naming]
[rule.var-declaration]
[rule.package-comments]
[rule.range]
[rule.receiver-naming]
[rule.time-naming]
[rule.unexported-return]
[rule.indent-error-flow]
[rule.errorf]
[rule.empty-block]
[rule.superfluous-else]
[rule.unused-parameter]
[rule.unreachable-code]
[rule.redefines-builtin-id]

现在,删除所有的注释,运行下面的命令来使用配置文件的linter。

revive -config revive.toml

要禁用这些规则中的任何一条,你可以删除它们,或者在指定的规则前添加# ,如下所示。

#[rule.exported]

在代码编辑器中设置提示功能

一些代码编辑器支持对代码进行自动提示,Visual Studio Code就是其中之一。

让我们看看如何在Visual Studio Code中设置revive linter。

打开VS Code,并为VS Code安装go 扩展。然后,选择 "文件"标签>"首选项">"设置",在搜索栏中添加go.lint ,并在Go:Lint工具部分选择revive

Go Lint in Search Field

Visual Studio Code默认的围棋衬垫工具是staticcheck

探索go vet 命令

与linters相比,go vet命令可以识别出那些可以编译但可能不会按预期执行的代码。

让我们考虑一下我们的Golang代码中一个常见的自赋值错误。更新main.go 文件,如下所示。

package main
import (
    "fmt"
)
func main() {
    PrintName("Emmanuel")
}
// revive:disable:exported
func PrintName(name string) {
    name = name
    fmt.Println(name)
}

即使有这个bug,上面的代码也会被编译。执行revive linter命令不会报告关于这个bug的任何问题。这时,go vet 命令就派上用场了。

运行go vet 命令,你应该有以下结果。

$ go vet
# sample
.\main.go:10:2: self-assignment of name to name

在Go中进行linting的替代包

如果revive不是你的首选,这里有一个由社区建立和维护的Go linters的列表。

golangci-lint

[golangci-lint](https://golangci-lint.run/)是一个快速的Go译码器运行器。它与每个主要的IDE集成,采用缓存,启用YAML配置,并行执行打火机,并附带大量的打火机。

静态检查

[staticcheck](https://staticcheck.io/)是一个最先进的Go编程语言编译器。它采用静态分析来识别错误和性能问题,提供简化,并执行风格指南。

结论

Go 认真对待文档,因为开发者越容易产生好的文档,对大家就越有利。

在这篇文章中,我们探讨了Golang中的打码,我喜欢的打码包,以及Go中打码的替代包。我希望你会喜欢用revive工作!