Go 如何避免恼人的错误“;声明和未使用;

Go 如何避免恼人的错误“;声明和未使用;,go,Go,我正在学习Go,但我觉得在编译时,我不应该保留任何未使用的变量或包,这有点烦人 这真的让我慢了下来。例如,我只是想声明一个新的包并计划稍后使用它,或者只是取消注释一些命令以进行测试。我总是得到错误,需要去评论所有这些用途 有没有办法避免这种登机手续 这个错误迫使您编写更好的代码,并确保使用您声明或导入的所有内容。它使阅读其他人编写的代码变得更容易(您始终确保使用所有声明的变量),并避免一些可能的死代码 但是,如果确实要跳过此错误,可以使用(): 变成 package main import (

我正在学习Go,但我觉得在编译时,我不应该保留任何未使用的变量或包,这有点烦人

这真的让我慢了下来。例如,我只是想声明一个新的包并计划稍后使用它,或者只是取消注释一些命令以进行测试。我总是得到错误,需要去评论所有这些用途


有没有办法避免这种登机手续

这个错误迫使您编写更好的代码,并确保使用您声明或导入的所有内容。它使阅读其他人编写的代码变得更容易(您始终确保使用所有声明的变量),并避免一些可能的死代码

但是,如果确实要跳过此错误,可以使用(
):

变成

package main

import (
    _ "fmt" // no more error
)

func main() {
    i := 1 // no more error
    _ = i
}
正如kostix在下面的评论中所说,您可以找到Go团队的官方立场:

存在未使用的变量可能表明存在错误,而未使用的导入只会降低编译速度。在代码树中积累足够多未使用的导入,事情会变得非常缓慢。出于这些原因,Go不允许任何一种情况

您可以为此使用简单的“空函数”,例如:

func Use(vals ...interface{}) {
    for _, val := range vals {
        _ = val
    }
}
# Install it
$ go get golang.org/x/tools/cmd/goimports

# -w to write the source file instead of stdout
$ goimports -w my_file.go
您可以这样使用:

package main

func main() {
    a := "declared and not used"
    b := "another declared and not used"
    c := 123

    Use(a, b, c)
}
这样,您就不必每次都定义
Use
函数:

import (
  "github.com/lunux2008/xulu"
)

func main() {
  // [..]

  xulu.Use(a, b, c)
}
根据:

有些人要求使用编译器选项来关闭这些检查,或者至少将它们减少为警告。但是,由于编译器选项不应影响语言的语义,并且由于Go编译器不报告警告,只报告阻止编译的错误,因此没有添加这样的选项

没有警告有两个原因。首先,如果它值得抱怨,那么它值得在代码中修复。(如果不值得修复,也不值得一提。)其次,让编译器生成警告会鼓励实现对可能导致编译噪音的弱情况发出警告,从而掩盖应该修复的实际错误

我不一定同意这一点,因为各种原因都不值得深入探讨。事实就是这样,在不久的将来不太可能改变

对于包,有一个工具可以自动添加丢失的包并删除未使用的包。例如:

func Use(vals ...interface{}) {
    for _, val := range vals {
        _ = val
    }
}
# Install it
$ go get golang.org/x/tools/cmd/goimports

# -w to write the source file instead of stdout
$ goimports -w my_file.go
你应该能够从任何一个半途而废的编辑器中运行它− 例如,对于Vim:

:!goimports -w %
goimports
页面列出了用于其他编辑器的一些命令,您通常将其设置为在将缓冲区保存到磁盘时自动运行

请注意,
goimports
也将运行
gofmt


如前所述,对于变量,最简单的方法是(暂时)将它们分配给

package main

import (
    "fmt" // imported and not used: "fmt"
)

func main() {
    i := 1 // i declared and not used
}
// No errors
tasty := "ice cream"
horrible := "marmite"

// Commented out for debugging
//eat(tasty, horrible)

_, _ = tasty, horrible

到目前为止没有提到的一个角度是用于编辑代码的工具集

与lukehoban的名为
Go
的扩展一起使用将为您带来一些自动魔力。Go扩展自动运行
gofmt
golint
等,并删除和添加
import
条目。所以至少这部分现在是自动的


我承认这并不是问题的100%答案,但无论多么有用。

如果其他人很难理解这一点,我认为用非常直截了当的术语来解释可能会有所帮助。如果您有一个不使用的变量,例如您已注释掉调用的函数(常见用例):

您可以将无用/空白变量分配给函数,使其不再未使用:


当我想在处理代码的另一部分时暂时禁用发送电子邮件时,我遇到了这个问题

注释服务的使用引发了很多级联错误,因此我使用了一个条件来代替注释

if false {
    // Technically, svc still be used so no yelling
    _, err = svc.SendRawEmail(input) 
    Check(err)
}

两年前我在学习Go时遇到了这个问题,所以我声明了自己的函数

// UNUSED allows unused variables to be included in Go programs
func UNUSED(x ...interface{}) {}
然后你可以这样使用它:

UNUSED(x)
UNUSED(x, y)
UNUSED(x, y, z)
它最大的优点是,你可以将任何东西传递到未使用的文件中

它比下面的好吗

_, _, _ = x, y, z

这取决于您。

据我所知,in-Go编译器看起来像是要注释掉的编译器。您应该能够构建自己的工具链,忽略这些适得其反的警告。

不过,这与注释它并没有太大区别。而且,我明白这是为了更好的代码,但是如果我们可以关闭一个检查,为什么在我们的代码上进行测试,然后在我们想要完成代码并使其干净之后再次打开这个检查,这会更好吗?FWIW,我读过别人的代码,但肯定不是因为未使用的符号。OTOH,我今天花了一个小时研究处理这个*%$golang“特性”的方法。遗憾的是,这个答案是正确的——但这并不能证明它是正确的。签入代码和简单地执行代码之间有着天壤之别。当我们签入代码时,我们使用linter来捕获这种错误。当我们在快速开发期间执行时,我们没有相同的标准。把编译器和linter混为一谈是不可原谅的。即使是谷歌内部的时尚警察也不会犯这样的错误。这是Go团队做出的愚蠢决定。特别是在试图调试东西时。让编译器将其视为错误是不可原谅的。有人可能会说这个问题是linter和代码样式规范的权限范围,但最终,每次我进行快速调试并注释几行代码时,都会出现将其作为编译错误的愚蠢行为。在我编译之前,必须通过注释掉块并注释掉所有在那里使用的声明,这是一种令人恶心的浪费。这会将2秒钟的调试习惯变成一个耗时30倍的过程。语言规范不应该把这条法令强加给我们。我仍然觉得编译器选项可能会对“我想注释一些东西以帮助调试”工作流有用。这项功能是浪费人们时间的好方法