闭包
Go 中闭包
闭包对捕获的外部变量并不是传值方式访问,而是以引用的方式访问。闭包的这种引用方式访问外部变量的行为可能会导致一些隐含的问题:
func main() {
for i := 0; i < 3; i++ {
defer func(){ println(i) } ()
}
}
// Output:
// 3
// 3
// 3
因为是闭包,在 for 迭代语句中,每个 defer 语句延迟执行的函数引用的都是同一个 i 迭代变量,在循环结束后这个变量的值为 3,因此最终输出的都是 3。修复的思路是在每轮迭代中为每个 defer 函数生成独有的变量。可以用下面两种方式:
func main() {
for i := 0; i < 3; i++ {
i := i // 定义一个循环体内局部变量i
defer func(){ println(i) } ()
}
}
func main() {
for i := 0; i < 3; i++ {
// 通过函数传入i
// defer 语句会马上对调用参数求值
defer func(i int){ println(i) } (i)
}
}
第一种方法是在循环体内部再定义一个局部变量,这样每次迭代 defer 语句的闭包函数捕获的都是不同的变量,这些变量的值对应迭代时的值。第二种方式是将迭代变量通过闭包函数的参数传入,defer 语句会马上对调用参数求值。