closure.go
文件信息
- 📄 原文件:
04_closure.go - 🔤 语言:go
完整代码
go
package main
import "fmt"
// ============================================================
// 匿名函数与闭包
// ============================================================
// 匿名函数:没有名字的函数,可以在需要时定义
// 闭包:可以访问其外部作用域变量的函数
//
// 【核心概念】闭包 = 函数 + 引用环境
// 闭包会"捕获"外部变量,即使外部函数已返回
func main04() {
fmt.Println("\n==================== 04_closure ====================")
fmt.Println("=== 匿名函数 ===")
// ----------------------------------------------------------
// 定义并立即调用
// ----------------------------------------------------------
// 语法: func(参数) 返回类型 { 函数体 }(实参)
result := func(a, b int) int {
return a + b
}(3, 4) // 立即调用
fmt.Println("立即调用匿名函数: 3 + 4 =", result)
// ----------------------------------------------------------
// 赋值给变量
// ----------------------------------------------------------
// 匿名函数可以赋值给变量,之后通过变量调用
multiply := func(a, b int) int {
return a * b
}
fmt.Println("multiply(5, 6) =", multiply(5, 6))
fmt.Println("multiply(7, 8) =", multiply(7, 8))
// 可以重新赋值
multiply = func(a, b int) int {
return a * b * 2 // 不同的实现
}
fmt.Println("新 multiply(5, 6) =", multiply(5, 6))
// ----------------------------------------------------------
// 闭包:捕获外部变量
// ----------------------------------------------------------
fmt.Println("\n=== 闭包基础 ===")
// 外部变量
counter := 0
// 闭包捕获 counter
increment := func() {
counter++ // 访问并修改外部变量
fmt.Println("counter =", counter)
}
increment() // counter = 1
increment() // counter = 2
increment() // counter = 3
fmt.Println("外部 counter =", counter) // 3
// ----------------------------------------------------------
// 闭包工厂:返回闭包
// ----------------------------------------------------------
fmt.Println("\n=== 闭包工厂 ===")
// 每次调用 makeCounter 都创建新的计数器
counter1 := makeCounter()
counter2 := makeCounter()
fmt.Println("counter1:", counter1()) // 1
fmt.Println("counter1:", counter1()) // 2
fmt.Println("counter1:", counter1()) // 3
fmt.Println("counter2:", counter2()) // 1(独立的计数器)
fmt.Println("counter2:", counter2()) // 2
fmt.Println("counter1:", counter1()) // 4(继续自己的计数)
// ----------------------------------------------------------
// 带参数的闭包工厂
// ----------------------------------------------------------
fmt.Println("\n=== 带参数的闭包工厂 ===")
addFive := makeAdder(5)
addTen := makeAdder(10)
fmt.Println("addFive(3) =", addFive(3)) // 8
fmt.Println("addTen(3) =", addTen(3)) // 13
fmt.Println("addFive(10) =", addFive(10)) // 15
// ----------------------------------------------------------
// 闭包陷阱:循环变量
// ----------------------------------------------------------
fmt.Println("\n=== 闭包陷阱:循环变量 ===")
// 【错误示例】
fmt.Println("错误方式:")
var funcsWrong []func()
for i := 0; i < 3; i++ {
funcsWrong = append(funcsWrong, func() {
fmt.Println(" i =", i) // 捕获的是同一个 i
})
}
for _, f := range funcsWrong {
f() // 全部输出 3!
}
// 【正确示例1】使用参数传递
fmt.Println("正确方式1(参数传递):")
var funcsRight1 []func()
for i := 0; i < 3; i++ {
funcsRight1 = append(funcsRight1, func(n int) func() {
return func() {
fmt.Println(" n =", n)
}
}(i)) // 立即传递当前值
}
for _, f := range funcsRight1 {
f()
}
// 【正确示例2】创建局部变量(Go 1.22+ 循环变量已改进)
fmt.Println("正确方式2(局部变量):")
var funcsRight2 []func()
for i := 0; i < 3; i++ {
i := i // 创建新的局部变量
funcsRight2 = append(funcsRight2, func() {
fmt.Println(" i =", i)
})
}
for _, f := range funcsRight2 {
f()
}
// ----------------------------------------------------------
// 闭包用途:延迟执行
// ----------------------------------------------------------
fmt.Println("\n=== 闭包用途:defer ===")
demoDefer()
// ----------------------------------------------------------
// 闭包用途:回调函数
// ----------------------------------------------------------
fmt.Println("\n=== 闭包用途:回调 ===")
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// 使用闭包作为过滤条件
evens := filter(numbers, func(n int) bool {
return n%2 == 0
})
fmt.Println("偶数:", evens)
// 使用闭包作为映射函数
doubled := mapSlice(numbers, func(n int) int {
return n * 2
})
fmt.Println("翻倍:", doubled)
// ----------------------------------------------------------
// 闭包用途:状态封装
// ----------------------------------------------------------
fmt.Println("\n=== 闭包用途:状态封装 ===")
// 类似于面向对象的私有状态
acc := makeAccumulator(100)
fmt.Println("初始余额: 100")
fmt.Println("存款 50:", acc(50))
fmt.Println("取款 -30:", acc(-30))
fmt.Println("存款 20:", acc(20))
// ----------------------------------------------------------
// 闭包 vs 结构体方法
// ----------------------------------------------------------
fmt.Println("\n=== 闭包 vs 结构体 ===")
// 闭包方式
fib := makeFibonacci()
fmt.Print("斐波那契(闭包): ")
for i := 0; i < 10; i++ {
fmt.Print(fib(), " ")
}
fmt.Println()
// 结构体方式(见 05_methods.go)
}
// ============================================================
// 闭包函数定义
// ============================================================
// ----------------------------------------------------------
// 闭包工厂:计数器
// ----------------------------------------------------------
// 每次调用返回一个新的计数器函数
// 每个计数器有自己独立的 count 变量
func makeCounter() func() int {
count := 0 // 这个变量被闭包捕获
return func() int {
count++
return count
}
}
// ----------------------------------------------------------
// 闭包工厂:加法器
// ----------------------------------------------------------
// 返回一个"加 n"的函数
func makeAdder(n int) func(int) int {
// n 被闭包捕获
return func(x int) int {
return x + n
}
}
// ----------------------------------------------------------
// 闭包工厂:累加器
// ----------------------------------------------------------
func makeAccumulator(initial int) func(int) int {
balance := initial
return func(amount int) int {
balance += amount
return balance
}
}
// ----------------------------------------------------------
// 闭包工厂:斐波那契生成器
// ----------------------------------------------------------
func makeFibonacci() func() int {
a, b := 0, 1
return func() int {
result := a
a, b = b, a+b
return result
}
}
// ----------------------------------------------------------
// defer 中的闭包
// ----------------------------------------------------------
func demoDefer() {
x := 10
// 方式1: 直接传值(值在 defer 时确定)
defer fmt.Printf(" defer 传值: x = %d\n", x)
// 方式2: 闭包捕获(值在执行时确定)
defer func() {
fmt.Printf(" defer 闭包: x = %d\n", x)
}()
x = 20
fmt.Println(" 函数中: x =", x)
}
// ----------------------------------------------------------
// 高阶函数:过滤
// ----------------------------------------------------------
func filter(nums []int, predicate func(int) bool) []int {
result := []int{}
for _, n := range nums {
if predicate(n) {
result = append(result, n)
}
}
return result
}
// ----------------------------------------------------------
// 高阶函数:映射
// ----------------------------------------------------------
func mapSlice(nums []int, mapper func(int) int) []int {
result := make([]int, len(nums))
for i, n := range nums {
result[i] = mapper(n)
}
return result
}
// ============================================================
// 重要注意事项
// ============================================================
//
// 1. 【闭包捕获变量的引用,不是值】
// 外部变量改变,闭包看到的值也变
// 闭包修改变量,外部也能看到
//
// 2. 【循环变量陷阱】
// Go 1.22 之前,循环变量是共享的
// Go 1.22+,每次迭代创建新变量
// 建议:总是显式创建局部变量
//
// 3. 【内存考虑】
// 闭包会持有外部变量的引用
// 可能导致变量无法被垃圾回收
// 长期运行的闭包要注意内存泄漏
//
// 4. 【闭包 vs 方法】
// 闭包:适合简单状态、临时使用
// 方法:适合复杂状态、需要多个操作
//
// 5. 【常见用途】
// - 延迟计算
// - 回调函数
// - 状态封装
// - 工厂函数
// - 装饰器模式
//
// 6. 【调试困难】
// 闭包没有名字,调试时栈信息不清晰
// 复杂场景考虑使用命名函数或方法
💬 讨论
使用 GitHub 账号登录后即可参与讨论