For loop for循环中goroutine的奇怪行为

For loop for循环中goroutine的奇怪行为,for-loop,go,goroutine,For Loop,Go,Goroutine,我正在从Python切换到GoLang。我在学高尔夫。在for循环中使用goroutines时,我遇到了奇怪的输出 package main import "fmt" func main() { var test = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,

我正在从Python切换到GoLang。我在学高尔夫。在for循环中使用goroutines时,我遇到了奇怪的输出

package main

import "fmt"

func main() {
    var test = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
        28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40}
    for _, x := range test{
        go func() {
            fmt.Println(x)
        }()
    }
}
输出:

25
19
28
19
40
40
6

我以为它是从for循环中捕获值,但当我看到它在增加和减少时。我弄糊涂了。为什么会发生这种情况?

goroutines正在访问与goroutines的执行并行变化的
x
变量。这是一个常见的问题,我想即使是go程序员也至少会遇到一次。您可以像下面这样捕获变量的当前值:

for _, x := range test{
    go func(x int) {
        fmt.Println(x)
    }(x)
 }
for _, x := range test{
    x2 := x
    go func() {
        fmt.Println(x2)
    }()
 }
或者像这样:

for _, x := range test{
    go func(x int) {
        fmt.Println(x)
    }(x)
 }
for _, x := range test{
    x2 := x
    go func() {
        fmt.Println(x2)
    }()
 }

另见@Marc,我不认为这个问题是非常准确的重复。它确实有一些重叠,因为这两个问题都是关于for循环中变量的范围和生存期的,但是goroutine版本没有显式地使用操作符的地址,并且goroutine在创建堆栈变量时没有复制堆栈变量这一点并不明显(如果您对该语言还不太了解的话)。但可能有一个更好的复制,因为这是一个很常见的问题。我很理解它可以从循环中随机选取值,但不理解为什么它会减少。