引言:
我们先来思考一个场景、老板要求你创建一个函数每次调用减一、你会怎么做?你可能会说简单、创建个全局变量、每次调用函数减一不就行了
var sum = 100
func main() {
sum--
fmt.Println(sum)
}但是全局变量1)所有代码都可以访问和修改、2)全局变量只有一个状态、3)全局变量多线程/协程并发访问时需要加锁。
显然是不行的啊、全局变量是无状态的、每次执行输出都是99、要不就存起来、执行的时候去读一下
package main
import (
"fmt"
"os"
"strconv"
)
const filename = "sum.txt"
func readSum() int {
data, err := os.ReadFile(filename)
if err != nil {
return 100 // 默认值
}
sum, _ := strconv.Atoi(string(data))
return sum
}
func writeSum(sum int) {
os.WriteFile(filename, []byte(strconv.Itoa(sum)), 0644)
}
func main() {
sum := readSum()
sum--
fmt.Println(sum)
writeSum(sum)
}这样写可以、但是这样好麻烦
闭包
有没有什么办法、能够简单实现刚才的需求呢?那就是使用闭包
闭包的4个必须条件
1.有函数嵌套2.内部函数引用外部作用域的变量参数3.返回值是函数4.创建一个对象函数、让其长期驻留接下来我们去实现一下
package main
import "fmt"
func decrementer() func() int {
sum := 100 // 初始值设为 100(可根据需求调整)
return func() int {
sum-- // 每次调用 sum 减 1
return sum
}
}
func main() {
dec := decrementer() // 创建闭包
fmt.Println(dec()) // 99 (100 - 1)
fmt.Println(dec()) // 98 (99 - 1)
fmt.Println(dec()) // 97 (98 - 1)
}这样就实现了老板的需求、打工人大喜
闭包的核心特点
1.捕获外部变量:可以访问并记住其定义时所在作用域的变量(即使外部函数已执行完毕)
func decrementer() func() int {
sum := 100 // 被闭包捕获的变量
return func() int {
sum-- // 操作的是 decrementer函数的 sum
return sum
}
}
2.变量声明周期延长:被闭包引用的变量不会随外部函数结束而销毁、其生命周期与闭包本身绑定、本质上是编译器在背后将变量从栈内存转移到了堆内存
dec := decrementer() // 创建闭包
fmt.Println(dec()) //sum存活
fmt.Println(dec()) //sum存活
fmt.Println(dec()) //sum存活3.状态保持:闭包在多次调用间维持捕获变量的状态、类似面向对象中的”私有属性“
dec := decrementer() // 创建闭包
fmt.Println(dec()) // 99 (100 - 1)
fmt.Println(dec()) // 98 (99 - 1) (记住前一次调用的状态)
fmt.Println(dec()) // 97 (98 - 1) (记住前一次调用的状态)Go4.隔离的数据环境、每个闭包独立:每次调用外部函数会创建新的闭包实例、各自持有独立的变量副本
dec1 := decrementer() // 创建闭包1、sum=100
dec2 := decrementer() // 创建闭包2、sum=100(与闭包1的sum无关)
fmt.Println(dec1()) //99 (100 - 1)
fmt.Println(dec2()) //99 (100 - 1)