非零基础自学Golang
文章目录
- 非零基础自学Golang
- 第7章 函数
- 7.5 匿名函数和闭包
- 7.5.1 定义和使用匿名函数
- 7.5.2 闭包的定义
- 7.5.3 闭包的“记忆力”
第7章 函数
7.5 匿名函数和闭包
匿名函数即在需要函数时定义函数,匿名函数能以变量方式传递,它常常被用于实现闭包。
首先,我们来了解什么是匿名函数以及它的调用方式。
7.5.1 定义和使用匿名函数
匿名函数的格式如下:
func (参数列表) (返回参数列表) {
函数体
}
匿名函数的调用有两种方式:
- 定义并同时调用匿名函数。
- 将匿名函数赋值给变量。
【1】定义并同时调用匿名函数
可以在匿名函数后添加“()”直接传入实参:
[ 动手写 7.5.1 ]
package main
import "fmt"
func main() {
func(data string) {
fmt.Println("Hello " + data)
}("world!")
}
运行结果
【2】将匿名函数赋值给变量
将匿名函数赋值给一个变量,之后再进行调用:
[ 动手写 7.5.2 ]
package main
import "fmt"
func main() {
f1 := func(data string) {
fmt.Println("Hello " + data)
}
f1("world!")
}
运行结果
7.5.2 闭包的定义
闭包就是包含了自由变量的匿名函数,其中的自由变量即使已经脱离了原有的自由变量环境也不会被删除,在闭包的作用域内可继续使用这个自由变量,同一个匿名函数和不同的引用环境组成了不同的闭包。
这个有点绕,一下没看懂没关系
闭包就如同有“记忆力”一般,可对作用域内的变量的引用进行修改。
对于闭包有许多应用,之后将会结合Go语言中的错误和异常进一步阐述闭包的作用。
7.5.3 闭包的“记忆力”
闭包可对作用域内变量的引用进行修改,在闭包内成功修改变量值后会对变量实际的值产生修改。
我们首先来看一个简单的例子:
[ 动手写 7.5.3 ]
package main
import "fmt"
func main() {
num := 1
fmt.Printf("%p\n", &num)
func() {
num++
fmt.Println(num)
fmt.Printf("%p\n", &num)
}()
func() {
num++
fmt.Println(num)
fmt.Printf("%p\n", &num)
}()
}
运行结果
以上程序中的匿名函数由于在函数体内部引用了外部的自由变量num而形成了闭包。
闭包每次对num变量的加1操作都是对变量num引用的修改。
[ 动手写 7.5.4 ]
package main
import "fmt"
func addOne(i int) func() int {
return func() int {
i++
return i
}
}
func main() {
a1 := addOne(0)
fmt.Println(a1()) // 0 + 1 = 1
fmt.Println(a1()) // 1 + 1 = 2
a2 := addOne(10)
fmt.Println(a2())
fmt.Print("a1闭包的地址为:")
fmt.Printf("%p\n", &a1)
fmt.Print("a2闭包的地址为:")
fmt.Printf("%p\n", &a2)
}
运行结果
addOne函数返回了一个闭包函数,通过定义a1和a2变量,创建了两个闭包的实例(引用环境不同导致)。
每次调用闭包实例,i的值都会在原有的基础上加1。从打印的结果可以看到,两个闭包实例的地址完全不同,两个闭包的调用结果互不影响。【 嗦嘎!!!】