什么是闭包

什么是闭包

文章通过一个“每次调用函数减一”的需求,引出了全局变量的弊端,并否定了直接使用文件存储的方式。最终,作者通过介绍闭包的四要素,并结合具体代码演示,清晰地展示了闭包如何优雅地解决这个问题,实现了状态的持久化和隔离。闭包的四大核心特点:捕获变量、延长变量生命周期、保持状态以及独立的运行环境,也得到了详细的阐述。

 次点击
7 分钟阅读

引言:

我们先来思考一个场景、老板要求你创建一个函数每次调用减一、你会怎么做?你可能会说简单、创建个全局变量、每次调用函数减一不就行了

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)

© 本文著作权归作者所有,未经许可不得转载使用。