首页 >后端开发 >Golang >Go 如何处理闭包中捕获的循环变量,以及为什么它很重要?

Go 如何处理闭包中捕获的循环变量,以及为什么它很重要?

Mary-Kate Olsen
Mary-Kate Olsen原创
2024-12-15 11:56:10805浏览

How Does Go Handle Captured Loop Variables in Closures, and Why Does it Matter?

Go 中捕获的闭包(for 循环变量)

理解循环变量闭包

在 Go 中,编译器可以自动捕获循环变量以在内部使用闭包,但这种行为根据循环类型而变化。在 for...range 循环中,循环变量被捕获为对外循环迭代变量的引用。

for...range 循环中引用闭包的原因

Go 对待 for.. .range 循环和其他 for 循环类似。因此,for...range 循环中循环变量的捕获闭包引用与外循环变量相同的内存位置。

引用闭包的后果

在这种情况下,任何修改对捕获的闭包变量所做的操作也会影响外循环的变量,可能会导致意外的行为。为了避免这个问题,有必要在闭包中创建循环变量的副本,如下面的“Value...range”示例所示。

示例代码

提供的代码代码片段说明了捕获循环变量的引用与捕获其值之间的区别:

func main() {
    lab1() // captured closure is not what is expected

    lab2() // captured closure is not what is expected

    lab3() // captured closure behaves ok
}

func lab3() {
    m := make(map[int32]int32)
    for i := 1; i <= 10; i++ {
        m[i] = i
    }

    l := [](func() (int32, int32)){}
    for k, v := range m {
        kLocal, vLocal := k, v // (C) captures just the right values assigned to k and v
        l = append(l, func() (int32, int32) {
            return kLocal, vLocal
        })
    }

    for _, x := range l {
        k, v := x()
        fmt.Println(k, v)
    }
}

func lab2() {
    m := make(map[int32]int32)
    for i := 1; i <= 10; i++ {
        m[i] = i
    }

    l := [](func() (int32, int32)){}
    for k, v := range m {
        l = append(l, func() (int32, int32) {
            kLocal, vLocal := k, v // (B) captures just the last values assigned to k and v from the range
            return kLocal, vLocal
        })
    }

    for _, x := range l {
        k, v := x()
        fmt.Println(k, v)
    }
}

func lab1() {
    m := make(map[int32]int32)
    for i := 1; i <= 10; i++ {
        m[i] = i
    }

    l := [](func() (int32, int32)){}
    for k, v := range m {
        l = append(l, func() (int32, int32) { return k, v }) // (A) captures just the last values assigned to k and v from the range
    }

    for _, x := range l {
        k, v := x()
        fmt.Println(k, v)
    }
}

输出

在 lab1 中,捕获的闭包引用循环中的最终值而不是预期的单个值。在 lab2 中,捕获仍然引用最终值,因为创建的闭包使用与外部作用域中其他地方引用的相同循环变量。在 lab3 中,闭包捕获循环变量的副本,因此它们准确地表示各个值。

以上是Go 如何处理闭包中捕获的循环变量,以及为什么它很重要?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn