文章目录
GoLang之闭包
1.闭包、自由变量定义
闭包的应该都听过,但到底什么是闭包呢?
闭包是由函数及其相关引用环境组合而成的实体(即:闭包=函数+引用环境)。
“官方”的解释是:所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
维基百科讲,闭包(Closure),是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。
支持闭包的语法可以发现一个特点,他们都有垃圾回收(GC)机制
2.普通函数不能引用main函数里的变量
函数也是一种类型
3.函数赋给变量不加括号是赋类型
func a() {
return
}
func main() {
c := a
fmt.Println(c)
}
4.函数赋给变量加括号是调用函数
报错是因为该函数没有返回值
4.%T查看函数类型
5.函数类型变量输出结果是指针
6.改变变量值后地址不会变
7.匿名函数里会改变到全局变量的值但不会改变地址
8.匿名函数作为返回值“:=”声明后可再当函数使用
9.匿名函数作为返回值被调用后可去原函数调用变量
10.匿名函数作为返回值var声明后可再当函数使用
func A(i int) {
i++
fmt.Println(i)
}
func C() func(a int) {
return A
}
func main() {
var f1 func() func(a int) = C
fmt.Println(f1())//0x7dc560
var f2 func(a int) = C()
f2(1)//2
}
11.闭包实例汇总
func a() {
i := 0
func() int {
i++
fmt.Println(i)
return i
}()
return
}
func main() {
a() //输出:1
a() //输出 1
}
func a() {
i := 0
func() int {
i++
fmt.Println(i)
return i
}()
return
}
func main() {
c := a
c()//输出:1
c()//输出:1
c()//输出:1
}
func a() func() int {
i := 0
b := func() int {
i++
fmt.Println(i)
return i
}
return b
}
func main() {
c := a()
c()//输出 1
c()//输出 2
c()//输出 3
}
func a() func() int {
i := 0
b := func() int {
i++
fmt.Println(i)
return i
}
return b
}
func main() {
a()//无任何输出
}
func a() func() int {
i := 0
b := func() int {
i++
fmt.Println(i)
return i
}
return b
}
func main() {
c := a()
c() //输出 1
c() //输出 2
c() //输出 3
d := a()
d()//1
d()//2
d()//3
}
以下程序中的匿名函数由于在函数体内部引用了外部的自由变量num而形成了闭包。闭包每次对num变量的加1操作都是对变量num引用的修改。
可以看出,物理地址没有发生变化,但是数值确发生变化,同时在第一个匿名函数中(闭包) 自变量n 发生变化,之后,n并没有重置,而是在基于保持该值,进入了第二个匿名函数中(闭包),n的数值继续发生变化,但是物理地址还是没有发生变化。
说明,在同一个作用域中(一个函数中,此处为 main(),当然可以为其他自定义的函数 ),闭包中的变量不会重置。