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

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

在围棋中,有什么方法可以避免这种检查吗?


当前回答

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

但是,如果你真的想跳过这个错误,你可以使用空白标识符(_):

package main

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

func main() {
    i := 1 // i declared and not used
}

就变成了

package main

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

func main() {
    i := 1 // no more error
    _ = i
}

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

未使用变量的存在可能表明存在错误,而未使用的导入只会降低编译速度。在代码树中积累足够多的未使用的导入,事情就会变得非常缓慢。由于这些原因,围棋两者都不允许。

其他回答

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

但是,如果你真的想跳过这个错误,你可以使用空白标识符(_):

package main

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

func main() {
    i := 1 // i declared and not used
}

就变成了

package main

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

func main() {
    i := 1 // no more error
    _ = i
}

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

未使用变量的存在可能表明存在错误,而未使用的导入只会降低编译速度。在代码树中积累足够多的未使用的导入,事情就会变得非常缓慢。由于这些原因,围棋两者都不允许。

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

注释服务的使用会触发很多级联错误,所以我使用了一个条件而不是注释

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

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

myFn := func () { }
// myFn()

你可以给函数赋值一个无用的/空白的变量,这样它就不再被使用了:

myFn := func () { }
_ = myFn
// myFn()

我的答案是黑进该死的信息源。这个补丁适用于1.19.4,然后你用-gcflags all=-nounusederrors构建源代码(你需要在其他地方帮助才能从源代码构建Golang):

tty/tty.go:98:6: hello declared but not used, but nobody cares

它不会抑制一些未使用的标签,并且附加消息的语法有点草率,但没有人会在意。

From 6eb19713fb5302ef2d5eb4af0c05e86c88d055c7 Mon Sep 17 00:00:00 2001
From: Daniel Santos <daniel.santos@pobox.com>
Date: Mon, 9 Jan 2023 21:56:03 -0600
Subject: Add -nounusedwarnings

---
 src/cmd/compile/internal/base/flag.go       |  1 +
 src/cmd/compile/internal/types2/errors.go   | 10 ++++++++++
 src/cmd/compile/internal/types2/labels.go   |  2 +-
 src/cmd/compile/internal/types2/resolver.go |  8 ++++----
 src/cmd/compile/internal/types2/stmt.go     |  4 ++--
 src/cmd/go/alldocs.go                       |  2 ++
 src/cmd/go/internal/work/build.go           |  2 ++
 src/go/types/gotype.go                      |  3 +++
 8 files changed, 25 insertions(+), 7 deletions(-)

diff --git a/src/cmd/compile/internal/base/flag.go b/src/cmd/compile/internal/base/flag.go
index a363b83984..f295746f64 100644
--- a/src/cmd/compile/internal/base/flag.go
+++ b/src/cmd/compile/internal/base/flag.go
@@ -111,6 +111,7 @@ type CmdFlags struct {
    MemProfileRate     int          "help:\"set runtime.MemProfileRate to `rate`\""
    MutexProfile       string       "help:\"write mutex profile to `file`\""
    NoLocalImports     bool         "help:\"reject local (relative) imports\""
+   NoUnusedErrors     bool         "help:\"no errors for unused imports and variables\""
    Pack               bool         "help:\"write to file.a instead of file.o\""
    Race               bool         "help:\"enable race detector\""
    Shared             *bool        "help:\"generate code that can be linked into a shared library\"" // &Ctxt.Flag_shared, set below
diff --git a/src/cmd/compile/internal/types2/errors.go b/src/cmd/compile/internal/types2/errors.go
index 2a3e88a2fe..0405fa26de 100644
--- a/src/cmd/compile/internal/types2/errors.go
+++ b/src/cmd/compile/internal/types2/errors.go
@@ -8,6 +8,7 @@ package types2
 
 import (
    "bytes"
+   "cmd/compile/internal/base"
    "cmd/compile/internal/syntax"
    "fmt"
    "runtime"
@@ -275,6 +276,15 @@ func (check *Checker) softErrorf(at poser, format string, args ...interface{}) {
    check.err(at, check.sprintf(format, args...), true)
 }
 
+func (check *Checker) unusedf(at poser, format string, args ...interface{}) {
+   if base.Flag.NoUnusedErrors {
+       pos := posFor(at)
+       fmt.Printf("%s: %s, but nobody cares\n", pos, check.sprintf(format, args...))
+   } else {
+       check.softErrorf(at, format, args)
+   }
+}
+
 func (check *Checker) versionErrorf(at poser, goVersion string, format string, args ...interface{}) {
    msg := check.sprintf(format, args...)
    if check.conf.CompilerErrorMessages {
diff --git a/src/cmd/compile/internal/types2/labels.go b/src/cmd/compile/internal/types2/labels.go
index 6f02e2fc96..d3ae602549 100644
--- a/src/cmd/compile/internal/types2/labels.go
+++ b/src/cmd/compile/internal/types2/labels.go
@@ -35,7 +35,7 @@ func (check *Checker) labels(body *syntax.BlockStmt) {
    for name, obj := range all.elems {
        obj = resolve(name, obj)
        if lbl := obj.(*Label); !lbl.used {
-           check.softErrorf(lbl.pos, "label %s declared but not used", lbl.name)
+           check.unusedf(lbl.pos, "label %s declared but not used", lbl.name)
        }
    }
 }
diff --git a/src/cmd/compile/internal/types2/resolver.go b/src/cmd/compile/internal/types2/resolver.go
index 5d498b6b2b..935435b03f 100644
--- a/src/cmd/compile/internal/types2/resolver.go
+++ b/src/cmd/compile/internal/types2/resolver.go
@@ -731,15 +731,15 @@ func (check *Checker) errorUnusedPkg(obj *PkgName) {
    }
    if obj.name == "" || obj.name == "." || obj.name == elem {
        if check.conf.CompilerErrorMessages {
-           check.softErrorf(obj, "imported and not used: %q", path)
+           check.unusedf(obj, "imported and not used: %q", path)
        } else {
-           check.softErrorf(obj, "%q imported but not used", path)
+           check.unusedf(obj, "%q imported but not used", path)
        }
    } else {
        if check.conf.CompilerErrorMessages {
-           check.softErrorf(obj, "imported and not used: %q as %s", path, obj.name)
+           check.unusedf(obj, "imported and not used: %q as %s", path, obj.name)
        } else {
-           check.softErrorf(obj, "%q imported but not used as %s", path, obj.name)
+           check.unusedf(obj, "%q imported but not used as %s", path, obj.name)
        }
    }
 }
diff --git a/src/cmd/compile/internal/types2/stmt.go b/src/cmd/compile/internal/types2/stmt.go
index 74d4164ba9..c4255e4413 100644
--- a/src/cmd/compile/internal/types2/stmt.go
+++ b/src/cmd/compile/internal/types2/stmt.go
@@ -66,7 +66,7 @@ func (check *Checker) usage(scope *Scope) {
        return unused[i].pos.Cmp(unused[j].pos) < 0
    })
    for _, v := range unused {
-       check.softErrorf(v.pos, "%s declared but not used", v.name)
+       check.unusedf(v.pos, "%s declared but not used", v.name)
    }
 
    for _, scope := range scope.children {
@@ -804,7 +804,7 @@ func (check *Checker) typeSwitchStmt(inner stmtContext, s *syntax.SwitchStmt, gu
            v.used = true // avoid usage error when checking entire function
        }
        if !used {
-           check.softErrorf(lhs, "%s declared but not used", lhs.Value)
+           check.unusedf(lhs, "%s declared but not used", lhs.Value)
        }
    }
 }
diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go
index a3c1fecb91..1f4c5c7b5c 100644
--- a/src/cmd/go/alldocs.go
+++ b/src/cmd/go/alldocs.go
@@ -179,6 +179,8 @@
 //     directory, but it is not accessed. When -modfile is specified, an
 //     alternate go.sum file is also used: its path is derived from the
 //     -modfile flag by trimming the ".mod" extension and appending ".sum".
+// -nounusederrors
+//     do not error on unused functions, imports, variables, etc.
 // -overlay file
 //     read a JSON config file that provides an overlay for build operations.
 //     The file is a JSON struct with a single field, named 'Replace', that
diff --git a/src/cmd/go/internal/work/build.go b/src/cmd/go/internal/work/build.go
index 5f11cdabaf..b37f1c8a01 100644
--- a/src/cmd/go/internal/work/build.go
+++ b/src/cmd/go/internal/work/build.go
@@ -135,6 +135,8 @@ and test commands:
        directory, but it is not accessed. When -modfile is specified, an
        alternate go.sum file is also used: its path is derived from the
        -modfile flag by trimming the ".mod" extension and appending ".sum".
+   -nounusederrors
+       do not error on unused functions, imports, variables, etc.
    -overlay file
        read a JSON config file that provides an overlay for build operations.
        The file is a JSON struct with a single field, named 'Replace', that
diff --git a/src/go/types/gotype.go b/src/go/types/gotype.go
index e8ff9658da..5a60b83346 100644
--- a/src/go/types/gotype.go
+++ b/src/go/types/gotype.go
@@ -47,6 +47,8 @@ The flags are:
        verbose mode
    -c
        compiler used for installed packages (gc, gccgo, or source); default: source
+   -nounusederrors
+       treat "unused" errors as warnings
 
 Flags controlling additional output:
 
@@ -104,6 +106,7 @@ var (
    allErrors  = flag.Bool("e", false, "report all errors, not just the first 10")
    verbose    = flag.Bool("v", false, "verbose mode")
    compiler   = flag.String("c", "source", "compiler used for installed packages (gc, gccgo, or source)")
+   nounusederr= flag.Bool("nounusederrors", false, "treat unused objects as warnings")
 
    // additional output control
    printAST      = flag.Bool("ast", false, "print AST")
-- 
2.38.2


免责声明:这不是一个全面的补丁-它只影响运行go构建或编译工具。当使用ast(树解析器),跟踪和其他一些工具时仍然应该有错误,因为我没有混乱的内部/类型,只有cmd/compile/internal/types2 - Golang源代码有点混乱。我希望他们能在某个时候进行重构,去掉这些冗余。

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