两个例子

package main

import (
	"fmt"
	"time"
)

func Process1(tasks []string) {
	for _, task := range tasks {
		// 启动协程并发处理任务
		go func() {
			fmt.Printf("Worker start process task: %s\n", task)
		}()
	}
}

func main() {

	tasks := []string{"1", "2", "3", "4", "5"}
	Process1(tasks)
	time.Sleep(2 * time.Second)
}
结果:
第一次运行
Worker start process task: 3
Worker start process task: 4
Worker start process task: 4
Worker start process task: 5
Worker start process task: 5
第二次运行
Worker start process task: 2
Worker start process task: 5
Worker start process task: 5
Worker start process task: 5
Worker start process task: 5

package main

import (
	"fmt"
	"time"
)

func Process1(tasks []string) {
	for _, task := range tasks {
		// 启动协程并发处理任务
		go func() {
			fmt.Printf("Worker start process task: %s\n", task)
		}()
	}
}

func Process2(tasks []string) {
	for _, task := range tasks {
		// 启动协程并发处理任务
		go func(t string) {
			fmt.Printf("Worker start process task: %s\n", t)
		}(task)
	}
}
func main() {
	tasks := []string{"1", "2", "3", "4", "5"}
	Process2(tasks)
	time.Sleep(2 * time.Second)
}
结果
第一次运行
Worker start process task: 5
Worker start process task: 4
Worker start process task: 2
Worker start process task: 3
Worker start process task: 1
第二次运行
Worker start process task: 2
Worker start process task: 5
Worker start process task: 4
Worker start process task: 1
Worker start process task: 3
for index, value := range xxxindexvalue

循环变量是易变的

首先,循环变量实际上只是一个普通的变量。

for index, value := range xxx

如果循环体中会启动协程(并且协程会使用循环变量),就需要格外注意了,因为很可能循环结束后协程才开始执行,
此时,所有协程使用的循环变量有可能已被改写。(是否会改写取决于引用循环变量的方式)

循环变量需要绑定

tasktask
tasktask

ps:

简单点来说

  • 如果循环体没有并发出现,则引用循环变量一般不会出现问题;
  • 如果循环体有并发,则根据引用循环变量的位置不同而有所区别
    • 通过参数完成绑定,则一般没有问题;
    • 函数体中引用,则需要显式地绑定

参照 topgoer的文章。