介绍
在很多语言中都有闭包的概念,比如js,python,lua以及java中的lambda表达式,go语言中也是有的
闭包其实就是一个函数引用了它所需要的一些变量组成的
在go语言中匿名函数就是一个闭包,下面使用一下匿名函数
Go 中的匿名函数
package main
import "fmt"
func main() {
a := 0
// 定义一个匿名函数
anonymousFunc := func() {
a++
fmt.Printf("匿名函数 %d\n", a)
}
// 匿名函数引用了 a 变量,每次执行方法,操作的变量应该总是同一个
anonymousFunc()
anonymousFunc()
anonymousFunc()
}
执行结果
匿名函数 1
匿名函数 2
匿名函数 3
Process finished with the exit code 0
根据执行结果验证了,一个匿名函数总是持有着函数外部变量的引用。这样也有一个坏处,导致变量得不到释放,如果运用的不好,会导致内存泄漏。
使用场景
举个例子,某平台给每个用户一些初始积分,用户每发布一片文章获得相应积分,并且不影响他人积分,代码如下
package main
import "fmt"
func main() {
// 创建账号
juanArticle, wendellArticle := accountRegister("juan"), accountRegister("wendell")
// 发布文章获得积分
juanArticle()
juanArticle()
wendellArticle()
wendellArticle()
wendellArticle()
}
// 注册某平台账号
func accountRegister(name string) func() {
integral := 10
// 返回发布文章执行函数
return func() {
integral += 10
fmt.Printf("用户%s 目前积分 %d\n", name, integral)
}
}
执行结果
用户juan 目前积分 20
用户juan 目前积分 30
用户wendell 目前积分 20
用户wendell 目前积分 30
用户wendell 目前积分 40
Process finished with the exit code 0
注意点
Go 使用闭包也有一些坑。比如下面一段代码,希望打印 4 3 2 1 0
package main
import "fmt"
func main() {
for i := 0; i < 5; i++ {
defer func() {
fmt.Println(i)
}()
}
}
执行结果
5
5
5
5
5
Process finished with the exit code 0
根据结果发现,打印的是 5 5 5 5 5,这是因为,每个匿名函数都引用了同一个变量,最终获取的都是一样的值。
解决匿名函数引用同一变量问题
方式一 每次都定义一个新的变量就行了
package main
import "fmt"
func main() {
for i := 0; i < 5; i++ {
i := i
defer func() {
fmt.Println(i)
}()
}
}
执行结果
4
3
2
1
0
Process finished with the exit code 0
方式二 将变量传入匿名函数作为行参,自然每次就引用的不是同一个变量了
package main
import "fmt"
func main() {
for i := 0; i < 5; i++ {
defer func(i int) {
fmt.Println(i)
}(i)
}
}
执行结果
4
3
2
1
0
Process finished with the exit code 0
以上就是对闭包的简单使用啦。大家使用的时候要避免出现变量受外界干扰的情况。
欢迎关注,学习不迷路!