我正在学习Go,但我觉得在编译时,我不应该留下任何未使用的变量或包,这有点烦人。
这真的让我慢下来了。例如,我只想声明一个新包并计划稍后使用它,或者只是取消某些命令的注释以进行测试。我总是得到错误,需要注释所有这些使用。
在围棋中,有什么方法可以避免这种检查吗?
我正在学习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团队的官方立场:
未使用变量的存在可能表明存在错误,而未使用的导入只会降低编译速度。在代码树中积累足够多的未使用的导入,事情就会变得非常缓慢。由于这些原因,围棋两者都不允许。
其他回答
2年前我在学习围棋的时候遇到了这个问题,所以我声明了自己的函数。
// 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
这取决于你。
我的答案是黑进该死的信息源。这个补丁适用于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源代码有点混乱。我希望他们能在某个时候进行重构,去掉这些冗余。
你可以使用一个简单的“null函数”,例如:
func Use(vals ...interface{}) {
for _, val := range vals {
_ = val
}
}
你可以这样使用:
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)
}
这个错误迫使您编写更好的代码,并确保使用您声明或导入的所有内容。它使阅读其他人编写的代码更容易(您总是可以确定所有声明的变量都将被使用),并避免一些可能的死代码。
但是,如果你真的想跳过这个错误,你可以使用空白标识符(_):
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团队的官方立场:
未使用变量的存在可能表明存在错误,而未使用的导入只会降低编译速度。在代码树中积累足够多的未使用的导入,事情就会变得非常缓慢。由于这些原因,围棋两者都不允许。
如果其他人很难理解这一点,我认为用非常直接的术语解释它可能会有所帮助。如果你有一个你不使用的变量,例如你已经注释掉调用的函数(一个常见的用例):
myFn := func () { }
// myFn()
你可以给函数赋值一个无用的/空白的变量,这样它就不再被使用了:
myFn := func () { }
_ = myFn
// myFn()