Go 函数可以是一个闭包。闭包是一个函数值,它引用了函数体之外的变量。 这个函数可以对这个引用的变量进行访问和赋值;换句话说这个函数被“绑定”在这个变量上。
我的不靠谱的理解,一个闭包相当于一个类的实例,函数体之外的变量相当于这个实例存储的变量。
没有闭包的时候,函数就是一次性买卖,函数执行完毕后就无法再更改函数中变量的值(应该是内存释放了);有了闭包后函数就成为了一个变量的值,只要变量没被释放,函数就会一直处于存活并独享的状态,因此可以后期更改函数中变量的值(因为这样就不会被go给回收内存了,会一直缓存在那里)。
闭包的主要意义myAdder1, myAdder2 := adder(), adder()
利用背包可以实现有自身状态的函数!
package main
import (
"fmt"
)
func adder() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
func main() {
myAdder := adder()
// 从1加到10
for i := 1; i <= 10; i++ {
myAdder(i)
}
fmt.Println(myAdder(0))
// 再加上45
fmt.Println(myAdder(45))
}
结果:
55 // 1+...+10
100
例子
利用闭包实现斐波拉契数列
package main
import (
"fmt"
)
func fibonacci() func() int {
b0 := 0
b1 := 1
return func() int {
tmp := b0 + b1
b0 = b1
b1 = tmp
return b1
}
}
func main() {
myFibonacci := fibonacci()
for i := 1; i <= 5; i++ {
fmt.Println(myFibonacci())
}
}
结果:
1
2
3
5
8
易错点
func B() []func() {
b := make([]func(), 3, 3)
for i := 0; i < 3; i++ {
b[i] = func() {
fmt.Println(i)
}
}
return b
}
func main() {
c := B()
c[0]()
c[1]()
c[2]()
}
结果:
// 因为都引用i,i最后变成了3
3
3
3
改正方法1:
package main
import (
"fmt"
)
func B() []func() {
b := make([]func(), 3, 3)
for i := 0; i < 3; i++ {
j := i
b[i] = func() {
fmt.Println(j)
}
}
return b
}
func main() {
c := B()
c[0]()
c[1]()
c[2]()
}
改正方法2:
package main
import (
"fmt"
)
func B() []func() {
b := make([]func(), 3, 3)
for i := 0; i < 3; i++ {
b[i] = func(j int) func(){
return func() {
fmt.Println(j)
}
}(i)
}
return b
}
func main() {
c := B()
c[0]()
c[1]()
c[2]()
}