Home > Backend Development > Golang > How Does Go Handle Captured Loop Variables in Closures, and Why Does it Matter?

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

Mary-Kate Olsen
Release: 2024-12-15 11:56:10
Original
804 people have browsed it

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

Captured Closure (for Loop Variable) in Go

Understanding Loop Variable Closures

In Go, the compiler can automatically capture loop variables for use within closures, but this behavior varies depending on the type of loop. In for...range loops, the loop variables are captured as references to the outer loop's iteration variables.

Reason for Reference Closures in for...range Loops

Go treats for...range loops and other for loops similarly. Therefore, the captured closure for a loop variable in a for...range loop references the same memory location as the outer loop's variable.

Consequences of Reference Closures

In this scenario, any modifications made to the captured closure's variable also affect the outer loop's variable, potentially leading to unexpected behavior. To avoid this issue, it's necessary to create a copy of the loop variable within the closure, as shown in the "Value...range" example below.

Example Code

The provided code snippet illustrates the difference between capturing a reference to the loop variable versus capturing its value:

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)
    }
}
Copy after login

Output

In lab1, the captured closures reference the final values from the loop instead of the expected individual values. In lab2, the captures still reference the final values because the created closure uses the same loop variables that are being referenced elsewhere in the outer scope. In lab3, the closures capture copies of the loop variables, so they accurately represent the individual values.

The above is the detailed content of How Does Go Handle Captured Loop Variables in Closures, and Why Does it Matter?. For more information, please follow other related articles on the PHP Chinese website!

source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template