Go语言for循环使用变量引用的坑
1、闭包捕获循环变量:
当在循环体内部使用闭包时,闭包可能会捕获同一个变量的引用,导致在闭包执行时变量值不符合预期。为了解决这个问题,可以在循环体内部创建一个临时变量,然后将其传递给闭包。
package main import "fmt" func main() { numbers := []int{1, 2, 3, 4, 5} var funcs []func() for _, num := range numbers { // 闭包捕获循环变量 funcs = append(funcs, func() { fmt.Println(num) }) } for _, f := range funcs { f() // 打印的是循环结束后的 num 值 } }
解决方法是在循环内部创建一个局部变量并将其传递给闭包:
package main import "fmt" func main() { numbers := []int{1, 2, 3, 4, 5} var funcs []func() for _, num := range numbers { localNum := num // 创建局部变量 funcs = append(funcs, func() { fmt.Println(localNum) }) } for _, f := range funcs { f() // 打印正确的 num 值 } }
2、循环变量作为goroutine参数:
在使用goroutine时,循环变量可能在goroutine执行之前被修改,导致goroutine捕获的值不一致。可以通过传递循环变量的副本解决这个问题。
package main import ( "fmt" "sync" ) func main() { var wg sync.WaitGroup for i := 0; i < 5; i++ { wg.Add(1) go func() { defer wg.Done() fmt.Println(i) // 打印的是循环结束后的 i 值 }() } wg.Wait() }
解决方法是传递循环变量的副本:
package main import ( "fmt" "sync" ) func main() { var wg sync.WaitGroup for i := 0; i < 5; i++ { wg.Add(1) go func(num int) { defer wg.Done() fmt.Println(num) // 打印正确的 i 值 }(i) } wg.Wait() }
小结:在Go语言中使用for
循环时可能遇到的一些变量引用的坑,通过小心处理变量的作用域和使用闭包可以避免这些问题。