Go语言为什么采用晚绑定?

创建一个空数组,数组元素类型为 void -> int 的函数,最后遍历数组并依次调用数组内的函数

~/go % cat arr_of_fns.go                 0:31 package main

import "fmt"

const LS_SIZE int = 5

func main() {
        // Creating empty array
        var fns [LS_SIZE]func() int
        // Loop
        for i := 0; i < LS_SIZE; i++ {
                fns[i] = func() int {
                        return i
                }
        }
        for n := 0; n < LS_SIZE; n++ {
                fmt.Printf("fns[%d]: %d\n", n, fns[n]())                                            }                                     }
~/go % go run arr_of_fns.go              0:31
fns[0]: 5
fns[1]: 5
fns[2]: 5
fns[3]: 5
fns[4]: 5
  • 循环变量 i 在离开循环块后就无法访问了,这一点和许多编译型语言一致
  • 但每个匿名函数返回的值一样,是循环变量最终的值,这一点又和 Python,Ruby,Groovy 等语言一样

为什么 Go 采用晚绑定?Ruby,Python 可以通过给函数添加默认参数,将每次循环的值保存下来。Go 要如何解决呢?

阅读 1.8k
2 个回答

除了一楼的方式外,你还可以:

package main

import "fmt"

const LS_SIZE int = 5

func main() {
    // Creating empty array
    var fns [LS_SIZE]func(x int) int    // 更改此处数组函数声明
    // Loop
    for i := 0; i < LS_SIZE; i++ {
        fns[i] = func(i int) int {        // 有入参
            return i
        }
    }
    for n := 0; n < LS_SIZE; n++ {
        fmt.Printf("fns[%d]: %d\n", n, fns[n](n))    // 带入入参
    }
}

输出:

fns[0]: 0
fns[1]: 1
fns[2]: 2
fns[3]: 3
fns[4]: 4

这种闭包问题很常见,fns的值在若干次循环中都是同一个内存地址,而i也在若干次循环后,更新到了 i++ 后的值。所以在你调用 fmt.Printf("fns[%d]: %d\n", n, fns[n]()) 的时候,不论是 fns[0]() 还是 fns[4]()等等,代表的都是同一个函数对象,fns[n]() 中i得值已经在上一个for循环执行完毕被更新到了5,而故而你最终得到的结果都是5.

func main() {
     
        var fns [LS_SIZE]func() int
     
        for i := 0; i < LS_SIZE; i++ {
                // 加个局部变量不就可以了
                idx := i
                fns[i] = func() int {
                        return idx
                }
        }
        for n := 0; n < LS_SIZE; n++ {
                fmt.Printf("fns[%d]: %d\n", n, fns[n]())
        }
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏