什么是闭包
怎样产生闭包
闭包可以让一个函数和一组变量产生关系,让这些变量的生命周期保持持久性。
变量可以是在闭包内部声明,也可以引用外部变量,例如:
// 在函数内部创建变量
func incr() func() int {
var x int
return func() int {
x++
return x
}
}
// 在函数外面创建变量
var x int
func incr() func() int {
return func() int {
x++
return x
}
}
在函数内部创建变量可以对外部进行隐藏,在外部声明变量可以在任意点修改。
闭包特点是:函数内部有引用外部变量,且有延迟执行的特点。
在golang中比较常见的就是遍历元素,启动一个协程去执行,例如:
for i := range data {
go func() {
fmt.Println(i)
}()
}
为了防止执行时i
的值相同,需要做一些出,例如:
for i := range data {
i := i
go func() {
fmt.Println(i)
}()
}
// 或者
for i := range data {
go func(i int) {
fmt.Println(i)
}(i)
}
闭包的用处
闭包最大的用处是利用延迟执行特性,进行一些操作。
go函数
启动定时任务,且可控制关闭它,可以使用闭包:
func startTicker(dur time.Duration) func() {
ticker := time.NewTicker(dur)
go func() {
for range ticker.C {
// do something
}
}()
return ticker.Stop
}
defer函数
常用模式还是在defer中使用闭包,而且defer+return的组合经常会让人摸不清头脑。
// 1.
func increaseA() int {
var i int
defer func() {
i++
}()
return i
}
// 2.
func increaseB() (r int) {
defer func() {
r++
}()
return r
}
defer中的函数将会在return后延迟执行,即先会确定返回值再执行defer函数。
这样会导致increaseA函数返回时拷贝i
值作为返回值,原有的i
去执行defer函数,并不会影响返回值。
而increaseB函数返回的是预先定义好的返回时的地址是确定的,这样defer函数改变的还是预先定义的r
值。