今天在看Go的语法,突然想对比一下python和Go的闭包机制的区别。
假如闭包调用循环变量,在Go中的实现方法为,循环中用一个新的变量保存这个循环变量的值,具体实现代码如下:
//Go
package main
import (
"fmt"
"reflect"
)
func main() {
var funcArray = count()
for index := range funcArray {
funcArray[index]()
}
}
func count() []func() {
var a = make([]func(), 3)
for index := range a {
indexCopy := index
a[index] = func() {
fmt.Println(indexCopy)
}
}
return a
}
三次循环中产生了三个新的indexCopy的量,于是这个程序最后打印出0, 1, 2.
但是在python中,必须这样实现:
#python
def count():
l = []
for i in range(3):
def f(i):
def g():
return i
return g
l.append(f(i))
return l
f1, f2, f3 = count()
print f1()
print f2()
print f3()
先构造一个函数f(i)把i的值固定住,加入list中,实现引用循环变量的功能。
这时候问题来了,为什么python不能像go一样,新建一个循环变量的拷贝,像下面这样呢:
#python
def count():
l = []
for i in range(3):
v = i
def f(i):
return v
l.append(f(i))
return l
这是python gc决定的。在for的三次循环中,变量v的地址是不变的,只是每次循环分别指向了常量区不同的常量。所以到了最后三个闭包函数所保存的v地址是一样的,而且都指向了常量区中的2,而Go中则是三个闭包函数保存着三个indexCopy变量的地址。