英文:
Using the variable on range scope `x` in function literal (scopelint)
问题
func TestGetUID(t *testing.T) {
namespace := "lkfm"
expecteduid := "fake_uid"
var tests = []struct {
description string
expected string
namespace string
objs []runtime.Object
}{
{"PositiveScenario", expecteduid, namespace, []runtime.Object{simpleNamespace(namespace)}},
}
for _, x := range tests {
t.Run(x.description, func(t *testing.T) {
client := fake.NewSimpleClientset(x.objs...)
actual := getUID(client, x.namespace)
assert.Equal(t, x.expected, actual)
})
}
}
Lint在以下代码上给我报了一些问题:
- client := fake.NewSimpleClientset(x.objs...)
- actual := getUID(client, x.namespace)
- assert.Equal(t, x.expected, actual)
并且报了这个错误:"在函数字面量中使用了范围作用域变量 x
(scopelint)"
英文:
func TestGetUID(t *testing.T) {
namespace := "lkfm"
expecteduid := "fake_uid"
var tests = []struct {
description string
expected string
namespace string
objs []runtime.Object
}{
{"PositiveScenario", expecteduid, namespace, []runtime.Object{simpleNamespace(namespace)}},
}
for _, x := range tests {
t.Run(x.description, func(t *testing.T) {
client := fake.NewSimpleClientset(x.objs...)
actual := getUID(client, x.namespace)
assert.Equal(t, x.expected, actual)
})
}
}
Lint give me some problem on :
- client := fake.NewSimpleClientset(x.objs...)
- actual := getUID(client, x.namespace)
- assert.Equal(t, x.expected, actual)
and it reports this error : "Using the variable on range scope x
in function literal (scopelint)"
答案1
得分: 14
x
是循环变量,在每次迭代中被重复使用。你创建了一个函数字面量,并将其传递给了t.Run()
。编译器无法确定在t.Run()
返回后是否会调用创建并传递的函数字面量,如果调用了函数字面量,它将引用循环变量,而循环变量将被下一次迭代的值覆盖。这往往不是我们想要的结果,这种情况通常会导致严重的错误,甚至在另一个goroutine中并发执行函数字面量时可能导致数据竞争。
因此,go vet
会对这种用法发出警告。
通常的解决方法是将循环变量的值作为参数传递给函数字面量,或者创建循环变量的副本并引用副本。由于你的函数字面量的签名是固定的(无法更改),你可以创建一个变量的副本,例如:
x2 := x
然后在函数字面量中引用x2
。这样go vet
就会满意了。
另外,由于复制变量的意图是明确的,你可以使用相同的名称,例如x := x
,这个副本将隐藏循环变量。在上述的短变量声明之后,标识符x
将引用局部副本(而不是循环变量)。一般情况下,这可能会引起混淆,但在这里意图是明确且可接受的。
英文:
x
is the loop variable which is reused in each iteration. And you create a function literal which you pass to t.Run()
. The compiler does not know (does not have guarantee) whether the created and passed function literal is not called after t.Run()
returns, in which case the function literal would refer to the loop variable which will be overwritten with the value of the next iteration. This is rarely–if ever–the intention. It's often the source of nasty bugs, even data race if the function literal is executed concurrently in another gorotuine.
So go vet
warns about such uses.
Often the solution is to pass the value of the loop variable to the function literal as an argument, or create a copy of the loop variable and refer to the copy. Since the signature of your function literal is fixed (you can't change it), create a copy of the variable, e.g.:
x2 := x
And refer to x2
inside the function literal. This will make go vet
happy.
Also, since the intention of making a copy is clear, you may use the same name, e.g. x := x
, which copy will shadow the loop variable. After the above short variable declaration, the identifier x
will refer to the local copy (and not the loop variable). In general this may cause confusion, but here the intention is clear and acceptable.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论