很多编程语言都闭包的概念,最常见闭包使用的应该是 javascript 了。其实闭包不是什么新奇的概念,就是函数与函数特定环境的组合,闭包使用了本函数之外定义的变量。Golang 中也有所谓的闭包,本文对Golang中的闭包的概念中的关键点通过实际示例进行个简单的说明。
示例1
package main
func add(base int) func(int) int {
return func(i int) int {
base += i
return base
}
}
func main() {
tmp1 := add(10)
fmt.Println(tmp(1),tmp(2))
tmp2 := add(100)
fmt.Println(tmp2(1),tmp2(2))
}
结果:
11 13 101 103
示例2
下面是个稍微复杂点的例子
func calc(base int) (func(int) int,func(int) int) {
add := func(i int) int {
base += i
return base
}
sub := func(i int) int {
base -= i
return base
}
return add,sub } func main() {
f1,f2 := calc(10)
fmt.Println(f1(1),f2(2))
fmt.Println(f1(3),f2(4))
fmt.Println(f1(5),f2(6))
fmt.Println(f1(7),f2(8))
}
结果
11 9 12 8 13 7 14 6
示例3
涉及 goroutine 时的情况
package main
import (
"fmt"
"time"
)
func main() {
for i:=0; i<5; i++ {
go func(){
fmt.Println(i)
}()
}
time.Sleep(time.Second)
}
结果:
5 5 5 5 5
通过这三个示例的结果,我们可以了解到闭包中绑定的是外层函数中的变量本身,不是变量当时的值。也就是说闭包中绑定变量的值可以不断变化。但是要注意函数的不同执行会产生不同的闭包,这些闭包之间的变量不是共享,因为函数的每次执行都会重新生成新的局部变量,使得闭包每次绑定的变量不同。
闭包引起的问题
最初使用 goroutine 的时候,曾遇到一个程序死锁的问题。思来想去看代码都觉得问题,最后发现是错误使用闭包导致的问题。
具体代码就不贴了,问题原型如下:
package main
import "fmt"
func main() {
cs := make([](chan int), 10)
for i := 0; i < len(cs); i++ {
cs[i] = make(chan int)
}
for i := range cs {
go func() {
cs[i] <- i
}()
}
for i := 0; i < len(cs); i++ {
t := <-cs[i]
fmt.Println(t)
}
}
出问题的就是这个地方
for i := range cs {
go func() {
cs[i] <- i
}()
}
由于goroutine还没有开始,i的值已经跑到了最大9,使得这几个goroutine都取的i=9这个值,从而都向cs[9]发消息,导致执行t := <-cs[i]
时,cs[0]
、cs[1]
、cs[2]
… 都阻塞起来了,从而导致了死锁。知道原因,改起来就容易了。
如下:
for i := range cs {
go func(index int) {
cs[index] <- index
}(i)
}
原文链接:https://www.f2er.com/go/190093.html