Golang语法系列——闭包函数

本文最后更新于:1 年前

常见坑

for语句的闭包中迭代变量使用不妥

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
data := []string{"one","two","three"}

wg := sync.WaitGroup{}
wg.Add(9)
//goroutines print: three, three, three
for _,v := range data {
go func() {
fmt.Println(v)
wg.Done()
}()
}

//goroutines print: one, two, three
for _,v := range data {
vcopy := v // 使用临时变量
go func() {
fmt.Println(vcopy)
wg.Done()
}()
}

//goroutines print: one, two, three
for _,v := range data {
go func(in string) {
fmt.Println(in)
wg.Done()
}(v)
}

wg.Wait()

在for迭代过程中,迭代变量v会一直保留,只是每次迭代值v不一样,因此在for循环中在闭包里直接引用迭代变量,在执行时直接取迭代变量的值,而不是闭包所在迭代的变量值

闭包要取所在迭代变量的值,需要for中定义临时变量来保存所在迭代的值,或者通过闭包函数传参


定义为指针数组时,输出正常

另一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
data := []field{{"one"},{"two"},{"three"}}
for _,v := range data {
// 解决办法:添加如下语句
// v := v
go v.print()
}
time.Sleep(3 * time.Second) //goroutines print: three, three, three

data2 := []*StructA{{"one"}, {"two"}, {"three"}} // 注意data2是指针数组 StructA 自定义结构
for _, v := range data2 {
go v.print() // go执行是函数,函数执行之前,函数的接受对象已经传过来
}
time.Sleep(3 * time.Second) //goroutines print: one, two, three