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循环时可能遇到的一些变量引用的坑,通过小心处理变量的作用域和使用闭包可以避免这些问题。

 

posted @ 2023-11-12 10:47  美好生活我心往之  阅读(375)  评论(0编辑  收藏  举报