Golang语法系列——闭包函数

本文最后更新于:5 年前

常见坑

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

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中定义临时变量来保存所在迭代的值,或者通过闭包函数传参


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

另一个例子:

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