Captured Closure (for Loop Variable) in Go

后端 未结 1 1942
感动是毒
感动是毒 2020-12-14 14:08

Shouldn\'t Go compiler capture for...range loop variables as a locally assigned closure variable?

Long Version:

This caused me some confusion in

相关标签:
1条回答
  • 2020-12-14 14:13

    Do you want the closure over the variable or the value? For example,

    package main
    
    import "fmt"
    
    func VariableLoop() {
        f := make([]func(), 3)
        for i := 0; i < 3; i++ {
            // closure over variable i
            f[i] = func() {
                fmt.Println(i)
            }
        }
        fmt.Println("VariableLoop")
        for _, f := range f {
            f()
        }
    }
    
    func ValueLoop() {
        f := make([]func(), 3)
        for i := 0; i < 3; i++ {
            i := i
            // closure over value of i
            f[i] = func() {
                fmt.Println(i)
            }
        }
        fmt.Println("ValueLoop")
        for _, f := range f {
            f()
        }
    }
    
    func VariableRange() {
        f := make([]func(), 3)
        for i := range f {
            // closure over variable i
            f[i] = func() {
                fmt.Println(i)
            }
        }
        fmt.Println("VariableRange")
        for _, f := range f {
            f()
        }
    }
    
    func ValueRange() {
        f := make([]func(), 3)
        for i := range f {
            i := i
            // closure over value of i
            f[i] = func() {
                fmt.Println(i)
            }
        }
        fmt.Println("ValueRange")
        for _, f := range f {
            f()
        }
    }
    
    func main() {
        VariableLoop()
        ValueLoop()
        VariableRange()
        ValueRange()
    }
    

    Output:

    VariableLoop
    3
    3
    3
    ValueLoop
    0
    1
    2
    VariableRange
    2
    2
    2
    ValueRange
    0
    1
    2
    

    References:

    The Go Programming Language Specification

    Function literals

    Function literals are closures: they may refer to variables defined in a surrounding function. Those variables are then shared between the surrounding function and the function literal, and they survive as long as they are accessible.

    Go FAQ: What happens with closures running as goroutines?

    To bind the current value of v to each closure as it is launched, one must modify the inner loop to create a new variable each iteration. One way is to pass the variable as an argument to the closure.

    Even easier is just to create a new variable, using a declaration style that may seem odd but works fine in Go.

    0 讨论(0)
提交回复
热议问题