【go语言】——什么是闭包?

在 Go 语言中,闭包(Closure)是一个非常重要的概念。它允许函数捕获并引用其外部作用域中的变量,即使这个外部作用域已经结束,被捕获的变量仍然可以被访问和修改。

1. 闭包

当一个匿名函数引用了其外层作用域中的变量时,这个组合就构成了闭包。这种机制让开发者可以在不改变全局命名空间的情况下共享数据,并且有助于构建更加模块化和易于维护的应用程序。

特性:

  • 闭包可以访问定义它的外部函数中的局部变量。
  • 即使外部函数已经返回,闭包仍然可以访问和修改这些变量。
  • 闭包在函数返回后仍然保持对外部变量的引用。

2. 闭包的基本形式

在 Go 中,闭包通常以匿名函数的形式出现,并且它可以捕获外部作用域中的变量。

如:

Go 复制代码
func a() func() int {
    i := 0
    b := func() int {
        i++
        fmt.Println(i)
        return i
    }
    return b
}
func main() {
    c := a()
    c() // 1
    c() // 2
    c() // 3
    a() // 没有信息输出
}
 
  • a函数定义了一个局部变量 i,并返回一个匿名函数 b 。
  • 这个匿名函数形成了一个闭包,因为它捕获了外部变量 i 。
  • 每次调用 c() 时,闭包会递增并返回 i 的值。
  • 即使 a 函数已经返回,闭包仍然可以访问和修改 i 。

直接调用 a() 不会输出任何信息,因为 a 函数本身并没有直接执行任何输出操作,仅仅是定义并返回一个嵌套函数 b 的引用。

3. 闭包的工作原理

(1) 变量捕获

当一个匿名函数引用了外部作用域中的变量时,Go 会确保这些变量在匿名函数返回后仍然存在。这种机制被称为"变量捕获"。

(2) 值捕获 vs 引用捕获
  • 在 Go 中,闭包捕获的是变量的引用,而不是变量的值。这意味着,闭包访问的是变量的当前值,而不是它在闭包创建时的值。
  • 这意味着多个闭包可以共享同一个外部变量的状态。
Go 复制代码
// 返回2个函数类型的返回值
func test01(base int) (func(int) int, func(int) int) {
    // 定义2个函数,并返回
    // 相加
    add := func(i int) int {
        base += i
        return base
    }
    // 相减
    sub := func(i int) int {
        base -= i
        return base
    }
    // 返回
    return add, sub
}

func main() {
    f1, f2 := test01(10)
    // base一直是没有消
    fmt.Println(f1(1), f2(2))
    // 此时base是9
    fmt.Println(f1(3), f2(4))
}

由此,我们可以解释闭包在稍后的时间点被调用时,产生的"延迟引用"现象,即闭包总是引用变量的当前值。

看下面这个例子:

Go 复制代码
function createFunctions() {
    var result = [];
    for (var i = 0; i < 3; i++) {
        result.push(function () {
            return i;
        });
    }
    return result;
}

var funcs = createFunctions();

console.log(funcs[0]()); // 输出 3
console.log(funcs[1]()); // 输出 3
console.log(funcs[2]()); // 输出 3
  • createFunctions 函数中,循环体内的匿名函数被添加到数组 result 中。
  • 这些匿名函数形成了闭包,它们捕获了变量 i 的引用。
  • 当循环结束时,变量 i 的最终值是 3(因为循环结束后 i 的值为 3)。
  • 因此,无论调用哪个匿名函数(funcs[0]()funcs[1]()funcs[2]()),它们都会返回 i 的当前值,即 3

由于闭包捕获的是变量的引用,而不是值,因此当闭包在稍后的时间点被调用时,它会访问变量的最新值,而不是它在闭包创建时的值。这就是所谓的"延迟引用现象"。

再看这个例子:

Go 复制代码
function createFunction() {
    var x = 10;
    var innerFunc = function () {
        console.log(x);
    };
    x = 20; // 修改变量 x 的值
    return innerFunc;
}

var func = createFunction();
func(); // 输出 20
  • createFunction 中,闭包 innerFunc 捕获了变量 x 的引用。
  • 在闭包创建之后,变量 x 的值被修改为 20
  • 当调用 func() 时,闭包访问的是变量 x 的当前值,即 20,而不是它在闭包创建时的值 10。

以上就是我对闭包的理解

相关推荐
是僵尸不是姜丝1 小时前
每日算法:洛谷U535992 J-C 小梦的宝石收集(双指针、二分)
c语言·开发语言·算法
小画家~1 小时前
第二十二: go与k8s、docker相关编写dockerfile
开发语言·golang·kubernetes
anlogic2 小时前
Java基础 4.12
java·开发语言
海涛高软2 小时前
qt mapFrom返回的QPoint和event->pos()区别和globalPos区别
开发语言·qt·命令模式
lauo2 小时前
智体知识库:ai-docs对分布式智体编程语言Poplang和javascript的语法的比较(知识库问答)
开发语言·前端·javascript·分布式·机器人·开源
草捏子2 小时前
主从延迟导致数据读不到?手把手教你架构级解决方案
后端
xiegwei2 小时前
Kotlin 和 spring-cloud-function 兼容问题
开发语言·kotlin·springcloud
橘猫云计算机设计3 小时前
基于Python电影数据的实时分析可视化系统(源码+lw+部署文档+讲解),源码可白嫖!
数据库·后端·python·信息可视化·小程序·毕业设计
Alt.93 小时前
SpringMVC基础二(RestFul、接收数据、视图跳转)
java·开发语言·前端·mvc
Yolo@~3 小时前
SpringBoot无法访问静态资源文件CSS、Js问题
java·spring boot·后端