英文:
golang Unusual Go Construct: Creating reusable Name: name := name .... Somethiing
问题
我在某个地方看到了这个用于在向函数发送数据时重复使用“名称”的结构。
我正在使用数据库,并且需要发送许多“命名”的缓冲区进行处理。这个结构看起来很完美,但我无法使其工作,并且无法记起在哪里看到过相关讨论。
任何帮助将不胜感激。
文本的要点是每次使用这个结构时,名称都会被重复使用,但每个实例实际上都是独立的。
我只记得它是 name := name ..然后是一些其他内容。我在这里迷失了。
英文:
I saw this construct somewhere for reusing a "name" when sending data to
a function.
I am working with a database and need to send a lot of "named" buffers to
be processed. This construct seems perfect, but I can not make work and
can not remember where I saw it discussed.
Any Help would be appreciated.
The jist of the text was that each time you used this contruct the name
would be used over and over, but each instance would be actually own it's
own for collection.
all I remember is that it was name := name ..then something. I am Lost here.
答案1
得分: 3
你肯定是在谈论创建循环变量的副本。通常,在这段代码中:
for i := 0; i < 100; i++ {
go func() {
fmt.Println(i)
}
}
i
在所有的 goroutine 中引用循环变量,所以如果 goroutine 在生成后,循环继续执行并在它们调用 fmt.Println(i)
之前,i
的值发生了变化,那么它们调用时的值就会与从循环生成它们时的值不同。解决这个问题的一种方法是,如你所提到的:
for i := 0; i < 100; i++ {
i := i
go func() {
fmt.Println(i)
}
}
添加的一行 i := i
引入了一个名为 i
的局部变量,并将其设置为等于循环变量 i
。这是两个不同的变量。你也可以说 j := i
,然后使用 j
。我倾向于认为使用 i := i
更令人困惑,但有些人更喜欢它。无论如何,由于它是一个局部变量,每次循环都会有一个不同的实例,这意味着每个 goroutine 都会看到自己独特的实例,不会被改变。
虽然这种习惯用法可以在 Effective Go 中找到(在页面上搜索 "req := req"),但我要明确一件事:这很令人困惑,应该避免使用。我不知道 Go 的作者为什么认为引入这种习惯用法是个好主意,在我看来,应该避免使用它。为什么呢?因为有一种更简洁的方式可以实现相同的效果,而且更容易理解:
for i := 0; i < 100; i++ {
go func(i int) {
fmt.Println(i)
}(i)
}
在这个版本中,匿名函数接受一个整数参数,当它在 goroutine 中生成时,循环变量 i
作为该参数传递。人们对这些语义有更牢固的理解,所以更容易看出这样做的效果,并理解它为什么有效。如果这仍然令人困惑,我建议更改参数名:
for i := 0; i < 100; i++ {
go func(j int) {
fmt.Println(j)
}(i)
}
我认为这两种方法更容易理解,应该使用它们来替代你提到的示例。
英文:
You're definitely referring to creating copies of loop variables. Normally, in this code:
for i := 0; i < 100; i++ {
go func() {
fmt.Println(i)
}
}
i
will reference the loop variable in all goroutines, so if the goroutines spawn and then the loop keeps going before they call fmt.Println(i)
, i
will be a different value when they call it than when they were spawned from the loop. One way around this is to do, as you mentioned:
for i := 0; i < 100; i++ {
i := i
go func() {
fmt.Println(i)
}
}
The added line, i := i
, introduces a local variable called i
, and sets it equal to the loop variable i
. These are two distinct variables. You might as well say j := i
and then use j
instead. I tend to think that using i := i
is more confusing, but some people prefer it. In any case, given that it's a local variable, there's a different instance of it per loop, which means that each goroutine sees its own unique instance that won't be changed.
While this idiom can be found in Effective Go (search for "req := req" on the page), let me be clear about something: this is confusing and should be avoided. I don't know why the Go authors thought it was a good idea to introduce this idiom, and, in my opinion, it should be avoided. Why? Because there's a much cleaner way to accomplish the same thing that is much more understandable:
for i := 0; i < 100; i++ {
go func(i int) {
fmt.Println(i)
}(i)
}
In this version, the anonymous function takes a single integer argument, and when it is spawned in a goroutine, the loop variable i
is passed as that argument. People have a much more solid understanding of these semantics, and so it's much easier to see what this does and understand why it works. If this is still confusing, I suggest changing the argument name:
for i := 0; i < 100; i++ {
go func(j int) {
fmt.Println(j)
}(i)
}
I think these two approaches are much more understandable and should be used instead of the example you mentioned.
答案2
得分: 0
你是不是指的是这样的结构:
func foo() {
var bar // 一些变量
go func() {
bar := bar // 将 bar 复制到内部作用域
}()
}
英文:
Did you mean a construct like this:
func foo() {
var bar // some variable
go func() {
bar := bar // copy bar into inner scope
}()
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论