闭包是:内层函数对外层变量的使用
例子:
package main
import "fmt"
func counter() func() {
i := 0
return func() { //闭包
i++ //i的作用域是整个counter函数
fmt.Println(i)
}
}
func main() {
counterFunc1 := counter()
for i := 0; i < 3; i++ {
counterFunc1()
}
counterFunc2 := counter()
counterFunc2()
}
1
2
3
1
闭包与for循环易出问题
case: for + goroutine
func main() {
for i := 0; i < 3; i++ {
go func() {
fmt.Println(i)
}()
}
select {} //为了等待goroutine执行看到输出
}
3
3
3
fatal error: all goroutines are asleep - deadlock!
输出不是0,1,2,而是i在for循环结束时的值3!
类似的,for里面,如果有函数体内使用到i,很可能是3
golang闭包中的坑
原因
内层函数与外层变量所在作用域不同
定义go func(){xxx} 时,变量i在外层作用域
运行时,沿作用域链向上层寻找
但是for循环运行很快,已经变成了3
所以go func都打印同一个值
这是一个新手常见问题 >.<
闭包为什么返回最后一个值
验证:如果给go func一些时间运行,会输出0,1,2
func main() {
for i := 0; i < 3; i++ {
go func() {
fmt.Println(i)
}()
time.Sleep(time.Second) //给go func一些时间运行
}
select {}
}
0
1
2
fatal error: all goroutines are asleep - deadlock!
解决
方法1:临时变量
func main() {
for i := 0; i < 3; i++ {
i := i
go func() {
fmt.Println(i)
}()
}
select {}
}
方法2:作为函数参数传入
func main() {
for i := 0; i < 3; i++ {
go func(i int) {
fmt.Println(i)
}(i)
}
select {}
}
输出顺序就看哪个goroutine先执行了,是不定的