如何避免恼人的错误"声明和未使用"

A-l*_*bby 195 go

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

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

Go有什么方法可以避免这种检查吗?

Flo*_*yle 199

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

但是,如果您确实想跳过此错误,可以使用空标识符(_):

package main

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

func main() {
    i := 1 // i declared and not used
}
Run Code Online (Sandbox Code Playgroud)

package main

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

func main() {
    i := 1 // no more error
    _ = i
}
Run Code Online (Sandbox Code Playgroud)

正如kostix在下面的评论中所说,你可以在FAQ中找到Go团队的官方立场:

存在未使用的变量可能表示存在错误,而未使用的导入只会减慢编译速度.在代码树中累积足够多的未使用的导入,事情会变得非常缓慢.由于这些原因,Go不允许.

  • 尽管如此,这与评论它并没有太大的不同.并且,我知道这是为了更好的代码,但是如果我们可以关闭检查为什么测试我们的代码然后在我们想要完成代码并使其干净之后再次打开此检查会更好吗? (82认同)
  • FWIW,我读过其他人的代码的时间很糟糕,但绝对不是因为未使用的符号.OTOH,我今天失去了一个小时调查处理这个*#%$ golang"功能"的方法. (23认同)
  • @kostix嗯..它可能不会减慢你的速度,因为你可能是一个专家,但它适合我和我编码的方式.我只是想知道是否有更好的方法.但无论如何,感谢FAQ!通过阅读本文,我完全可以理解golang这样做的原因. (20认同)
  • 可悲的是,这个答案是正确的 - 但这并不合理.检查代码和执行代码之间存在着天壤之别.当我们签入代码时,我们使用linters来捕获这种错误.当我们在快速开发期间执行时,我们没有相同的标准.将编译器与linter混淆是不可原谅的.甚至谷歌内部的风格警察都没有犯这个错误. (19认同)
  • 是否有一个命令行参数来关闭它?或者这是一个不可更改的功能? (18认同)
  • 让编译器将此视为错误是不可原谅的。可以说这个问题是linters和代码样式规范的权限,但最终,每次我进行一些快速调试并注释掉几行代码时,都会出现使它成为编译错误的愚蠢现象。必须经过注释掉的块并注释掉所有在那里使用的声明,然后才能进行编译,这是令人不快的浪费。这将2秒钟的调试习惯变成了一条耗时30倍的日志。语言规范并没有强加于我们的这项法令。 (12认同)
  • 这是Go团队的一个愚蠢的决定.特别是在尝试调试时. (11认同)
  • @LostCrotchet:语言设计者应该专注于帮助程序员编写好的代码的方法,而不是试图阻止他们编写糟糕的代码,或者更糟糕的是,阻止他们以语言设计者不这样做的方式编写满足程序员目标的代码。不喜欢。 (5认同)
  • 这绝对是一个错误。Google 认为他们比过去 70 年来的计算机科学家更了解——我不知道为什么 Thompson 没有反驳这一点。到现在我已经编程 36 年了。我需要针对这些警告,因为我正在非常快地编写代码并进行许多调整和实验。这个“功能”很麻烦,在快速开发的同时迫使进行不必要的代码修改。在其他语言中,我的最终构建错误警告,但将其吐出,有时在开发时抑制一些错误。这必须修改——这是愚蠢的。 (5认同)
  • @A-letubby,Go开发者的官方职位是[在FAQ](http://golang.org/doc/faq#unused_variables_and_imports); 如果你不能忍受这个,你可以做的并不多.我个人的观点是"相当慢"是一种高估:它需要我一次"go build"来评论/删除任何不需要的东西,而且速度很快.而且你知道生成的程序有很大的机会是正确的 - 与脚本语言相反,修改运行周期更快,你会在错误中得到运行时崩溃(读取:未使用的变量). (4认同)
  • 我认为这种风格的警察文化阻碍了发展。例如,我现在正在写测试;我正在定义大量数组(我不太确定目前要做什么 - 但我知道我将使用这些数组中的数据进行测试)并且我只想检查一下我正在使用所有正确的语法进行编写,并且我在编写过程中没有错误地使用库。当我编译代码以检查“真正”错误时,错误输出中充满了红色鲱鱼(即不使用我刚刚声明的数组)。 (4认同)
  • 我正在编写一些代码,只不过是修补/正在进行中,我只想运行调试器来验证、检查、玩弄一些结果。但因为我实际上并没有修改上述结果,所以无法编译。这令人沮丧。使用 _ = <var> 的答案似乎可以解决我的简单情况,但这并不能成为阻止编译我未签入的代码的借口。关闭它的选项应该存在。 (3认同)
  • 如果人们想要一个选项来抑制该错误,则意味着这对他们有利。它不会强迫您编写更好的代码。人们是否无法理解最终产品和产品开发之间的差异?对于所谓的实用语言来说,这是多么教条的决定。 (3认同)
  • 我的回答是:“ Go不是令人讨厌的语言。它是一种故意的令人讨厌的语言”。那信天翁不会为收养做任何事情。 (3认同)
  • Go团队的立场完全没有抓住重点。就好像他们只在书本上读过有关软件开发的内容,而从未亲自实践过一样!我同意这是一个很棒的功能,即使默认情况下也是如此,但是在调试时这只是一种巨大的时间浪费,而且绝对是不必要的,这可以通过“不发布构建的代码”的简单策略来避免带有-抑制警告”。 (3认同)
  • 我在哪里可以修改 Go 编译器来禁用这个*脏话*烦人的警告? (2认同)
  • 当变量未被使用时,Go 会引发编译错误,但当函数的输出被忽略时,Go 不会抱怨。这是不一致的。忽略输出更糟糕,因为它可能会忽略错误,或者只是忽略函数结果。虽然未使用的变量将在堆等上占用 64 位,但这是完全可以忽略的,并且与代码质量和性能无关 (2认同)

Mar*_*oij 26

根据FAQ:

有些人要求使用编译器选项来关闭这些检查,或者至少将它们减少为警告.这样的选择还没有被添加,但是,因为编译器选项不会影响语言的语义,因为围棋编译器不报告警告,只是防止编译错误.

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

由于各种原因,我不一定同意这一点.它就是这样,它不太可能在不久的将来改变.

对于软件包,有一个goimports工具可以自动添加缺少的软件包并删除未使用的软件包.例如:

# Install it
$ go get golang.org/x/tools/cmd/goimports

# -w to write the source file instead of stdout
$ goimports -w my_file.go
Run Code Online (Sandbox Code Playgroud)

您应该可以从任何中途正确的编辑器运行它 - 例如对于Vim:

:!goimports -w %
Run Code Online (Sandbox Code Playgroud)

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

请注意,goimports也会运行gofmt.


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

// No errors
tasty := "ice cream"
horrible := "marmite"

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

_, _ = tasty, horrible
Run Code Online (Sandbox Code Playgroud)

  • “Go 编译器不会报告警告,只会报告阻止编译的错误。” 有用的信息,但语言作者的方法很糟糕 (6认同)
  • 这是对Monty Python和The Holy Grail([this](https://youtu.be/M9DCAFUerzs?t=39))@mrbarletta场景的一个玩笑/引用。我想如果您不了解参考文献,可能会显得有些奇怪。我用一个不同的笑话代替了它。 (2认同)
  • 是的,很难同意。我正在自己测试 Go,遇到这些“错误”不是因为代码需要修复,而是因为代码尚未完成。如果我想在调试过程中注释掉某些内容...由于未使用的变量,我需要重新处理其他部分。 (2认同)

小智 22

您可以使用简单的"空函数",例如:

func Use(vals ...interface{}) {
    for _, val := range vals {
        _ = val
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以这样使用:

package main

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

    Use(a, b, c)
}
Run Code Online (Sandbox Code Playgroud)

还有一个包,所以你不必Use每次都定义函数:

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

func main() {
  // [..]

  xulu.Use(a, b, c)
}
Run Code Online (Sandbox Code Playgroud)

  • 有没有办法自动使用所有声明的值?出于开发目的,这个问题真的很烦人=/ (6认同)
  • 看来循环是不必要的,请参阅下面的答案 /sf/answers/4406593761/ (3认同)

chu*_*acw 12

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

// UNUSED allows unused variables to be included in Go programs
func UNUSED(x ...interface{}) {}
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样使用它:

UNUSED(x)
UNUSED(x, y)
UNUSED(x, y, z)
Run Code Online (Sandbox Code Playgroud)

它的伟大之处在于,您可以将任何内容传递给 UNUSED。

比下面的好吗?

_, _, _ = x, y, z
Run Code Online (Sandbox Code Playgroud)

随你(由你决定。

  • 我发现这种方法比空白标识符更有用...当我在 go 中开发时,我喜欢尽早且尽可能频繁地运行我的代码...对我来说,使某些变量“未使用”更有用我的最后一行,而不是注释掉可能无法按我预期工作的整个块。 (3认同)

max*_*ner 10

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

myFn := func () { }
// myFn()
Run Code Online (Sandbox Code Playgroud)

您可以为函数分配一个无用/空白变量,使其不再使用

myFn := func () { }
_ = myFn
// myFn()
Run Code Online (Sandbox Code Playgroud)


max*_*ime 9

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

评论服务的使用引发了很多级联错误,因此我没有使用评论,而是使用了一个条件

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


mil*_*onb 8

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

使用Visual Studio代码与扩展一起lukehobanGo会做一些自动魔术给你.转到扩展自动运行gofmt,golint等等,以及删除和添加import条目.所以至少那部分现在是自动的.

我承认它不是100%的问题解决方案,但无论多么有用.


Pet*_*ron 5

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