版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/netdxy/article/details/72054431
Go里有函数类型的变量,这样,虽然不能在一个函数里直接声明另一个函数,但是可以在一个函数中声明一个匿名函数类型的变量,此时的匿名函数称为闭包(closure)。
先看一个demo:
func f(i int) func() int {
return func() int {
i++
return i
}
}
函数f返回了一个函数,返回的这个函数就是一个闭包。这个函数中本身是没有定义变量i的,而是引用了它所在的环境(函数f)中的变量i。
我们再看一下效果:
c1 := f(0)
c2 := f(0)
c1() // 打印 1
c2() // 打印 1
c1 跟 c2 引用的是不同的环境,在调用 i++ 时修改的不是同一个 i,因此两次的输出都是 1。函数 f 每进入一次,就形成了一个新的环境,对应的闭包中,函数都是同一个函数,环境却是引用不同的环境。
再看几个例子
package main
import "fmt"
func ExFunc(n int) func() {
sum := n
a := func() { // 把匿名函数作为值赋给变量a (Go 不允许函数嵌套, 然而你可以利用匿名函数实现函数嵌套)
fmt.Println(sum + 1) // 调用本函数外的变量
} // 这里没有()匿名函数不会马上执行
return a
// 或者直接 return 匿名函数
// return func() { //直接在返回处的匿名函数
// fmt.Println(sum + 1)
// }
}
func main() {
myFunc := ExFunc(10)
myFunc() // 这里输出11
myAnotherFunc := ExFunc(20)
myAnotherFunc() // 这里输出21
myFunc() // 这里输出11
myAnotherFunc() // 这里输出21
}
另一个例子:
package main
import "fmt"
func ExFunc(n int) func() {
return func() {
n++ // 这里对外部变量加 1
fmt.Println(n)
}
}
func main() {
myFunc := ExFunc(10)
myFunc() // 这里输出 11
myAnotherFunc := ExFunc(20)
myAnotherFunc() // 这里输出 21
myFunc() // 这里输出 12
myAnotherFunc() // 这里输出 22
}
由此得出以下两点
1.内函数对外函数 的变量的修改,是对变量的引用
2.变量被引用后,它所在的函数结束,这变量也不会马上被烧毁
闭包函数出现的条件:
1.被嵌套的函数引用到非本函数的外部变量,而且这外部变量不是“全局变量”;
2.嵌套的函数被独立了出来(被父函数返回或赋值 变成了独立的个体),而被引用的变量所在的父函数已结束.