Go 语言中的闭包
本文主要介绍 Go 语言中的闭包。简单的说 Go 语言的闭包就是一个引用了外部自由变量的匿名函数,被引用的自由变量和该匿名函数共同存在,不会因为离开了外部环境就被释放或者删除,还可以在这个匿名函数中继续使用。
1. Go 语言的匿名函数
在上文中我们了解到了一个新的词汇——匿名函数,我们先来学习一下Go语言中的匿名函数,再来了解在 Go 语言中如何使用闭包。匿名函数,顾名思义,就是隐藏函数名的函数。
代码示例:
package main
import (
"fmt"
)
var f = func() {
fmt.Println("匿名函数作为变量来使用")
}
func main() {
f()
func() {
fmt.Println("匿名函数直接使用")
}()
}
- 第7~9行:定义一个函数类型,值为一个匿名函数的变量;
- 第 12 行:使用这个匿名函数;
- 第 14~16 行:定义一个匿名函数。在这个函数后加上
()
,就可以直接使用这个匿名函数。
执行结果:
2. 匿名函数引用外部变量
如果在匿名函数内,使用了外部环境的变量,就构成了一个闭包。简单来讲就是一个函数内,使用匿名函数来操作函数内声明的变量。
代码示例:
package main
import (
"fmt"
)
func main() {
str := "Hello World!"
func() {
str = "Hello Codey!"
}()
fmt.Println(str)
}
- 第 10 行:匿名函数直接操作了main函数之中的变量str,将其修改为了"Hello Codey!";
- 第 12 行:输出变量的值。
执行结果:
上述例子简单的构造了一个闭包,在匿名函数中并没有声明或者定义str这个变量,但是可以直接操作,就是引用可main函数中的自由变量。这个例子可能对自由变量的引用表现不是很直观,我们接下来使用defer和闭包相结合,深入了解一下闭包中的引用外部变量。
代码示例:
package main
import (
"fmt"
)
func main() {
str := "Hello World!"
defer func() {
fmt.Println("defer str=", str)
}()
str = "Hello Codey!"
fmt.Println("main str=", str)
}
执行结果:
从执行结果上来看应该是蛮出人意料的,因为前文介绍 defer 的时候明确介绍了 defer 后变量是保留它在 defer 时的值,而不会被 defer 之后的代码所改变。但是在闭包这边这个看起来不太适用,其实是适用的,只是闭包是引用了这个变量,也就是说,在 defer 时被保留下来的是这个变量的地址,后续代码改变的不是地址,而是这个地址存储的值,所以后续代码对这个变量的操作,都会反应到这个 defer 中。
Tips:关于变量的地址,在后续的Go语言的指针中会有详细的介绍。
3. 小结
本文主要介绍了 Go 语言中闭包的使用,需要注意以下几点:
- 闭包就是匿名函数引用外部变量
- 闭包中引用的变量会被外部环境改变,同时闭包内对变量的改变也会影响到外部环境的使