闭包
概念说明
闭包可以理解为“函数 + 它引用的外部变量”。
外层函数执行结束后,内层函数仍然可以继续使用这些被捕获的变量。
它适合实现延迟执行、计数器、配置函数等场景。
语法/规则
- 闭包本质是返回一个匿名函数,且匿名函数引用了外层变量。
- 被捕获的变量会在后续调用中持续生效。
- 闭包逻辑应尽量保持单一职责,避免过度嵌套影响可读性。
延时求和示例
目标:先传入延时参数,再传入多个整数并求和。
使用方式:awaitAdd(2)(1, 2, 3)。
| |
逐行解释(核心函数)
先只看核心这段:
| |
逐行解释如下:
func awaitAdd(delaySecond int) func(...int) int {
定义外层函数awaitAdd。
它接收一个参数delaySecond(延时秒数),返回值不是普通值,而是“另一个函数类型”func(...int) int。return func(numList ...int) int {
返回一个匿名函数。这个匿名函数接收多个整数(可变参数),并返回一个整数(求和结果)。time.Sleep(time.Duration(delaySecond) * time.Second)
先暂停delaySecond秒。这里用了外层函数的变量delaySecond,这就是闭包捕获外部变量。sum := 0
定义累加器,初始值为 0。for _, num := range numList {
遍历传进来的所有整数参数。sum += num
把每个数字累加到sum。return sum
把累加结果返回给调用方。最后的
}}}
依次结束:匿名函数体、return func语句所在块、外层函数体。
逐行解释(调用代码)
| |
awaitAdd(2):先调用外层函数,得到一个“已经记住延时 2 秒”的新函数。(1, 2, 3):再调用这个新函数,传入要相加的数字。fmt.Println(...):打印返回结果。
逻辑串联(从调用到返回)
把整句 awaitAdd(2)(1, 2, 3) 连起来看:
- 第一步:
awaitAdd(2)创建并返回一个内部函数。 - 第二步:内部函数拿到
1,2,3后先等待 2 秒。 - 第三步:遍历
1,2,3,计算总和6。 - 第四步:把
6返回给fmt.Println输出。
等价写法(更容易看懂):
| |
输出结果(等待约 2 秒后):
| |
常见错误
- 误把延时逻辑放在外层函数里,导致“创建闭包时延时”而不是“调用时延时”。
- 在循环中错误捕获变量,导致多个闭包共享同一最终值。
- 闭包层级过深且无注释,后期维护困难。
- 把两次调用写成一次传参(如
awaitAdd(2, 1, 2, 3)),会因为参数不匹配而编译失败。