闭包就是一个函数和与其相关的引用环境组合而成的整体。换句话说,闭包允许函数访问并操作函数外部的变量,即使外部函数已经返回。
一、闭包的要素包括:
- 函数:闭包必须包含一个函数,可以是匿名函数或具名函数。
- 引用环境:闭包必须引用至少一个外部变量,这些变量在函数定义时存在,并且在函数执行时仍然可访问。
二、闭包的作用:
- 数据封装:闭包可以将函数内部的变量封装起来,防止外部直接访问和修改,从而实现数据的私有化。
- 维持状态:闭包可以维持函数执行时的状态,即使外部函数已经返回,闭包仍然可以访问和修改这些状态。
三、示例
- Calc 是一个函数,返回的类型是 func(y int) int,这个返回的函数就是一个闭包。
- 闭包内部访问了外部函数 Calc 的变量 count,并且每次调用闭包时都可以修改这个变量。
- 当我们反复调用 c 函数时,count 只初始化一次,并且在每次调用 c 时都会累加 y 的值,体现了闭包维持状态的特性。
package main
import "fmt"
// 闭包
func Cal(x int) func(y int) int {
count := x // 定义一个外部变量 count
return func(y int) int {
count += y // 内层函数访问并修改外部变量 count
return count
}
}
func main() {
c := Cal(10) // 调用 Cal 函数,返回一个闭包函数
fmt.Println(c(1)) // 输出 11
fmt.Println(c(1)) // 输出 12
fmt.Println(c(1)) // 输出 13
}
四、使用普通函数实现上面 Cal 函数的效果,需要通过指针参数传递和修改外部变量,这样会使得函数调用变得复杂和不直观。而使用闭包则可以直接访问和修改外部变量,使得代码更加简洁和易读。
package main
import "fmt"
func Cal1(c1 *int, y int) *int {
*c1 += y // 通过指针参数传递和修改外部变量
return c1
}
func main() {
c1 := 10 // 需要额外定义一个外部变量 c1
fmt.Println(Cal1(&c1, 1)) // 输出 11
fmt.Println(Cal1(&c1, 1)) // 输出 12
fmt.Println(Cal1(&c1, 1)) // 输出 13
}