08 - Go 函数(中):匿名函数、闭包与函数式编程

文章目录


🚀 08 - Go 函数(中):匿名函数、闭包与函数式编程

在上一篇中,我们已经掌握了 Go 函数的基础用法(定义、参数、返回值等)。

但如果只停留在基础,其实还远远不够应对实际开发和面试

这一篇,我们进入真正的"进阶核心":

👉 匿名函数

👉 闭包(面试高频🔥)

👉 函数作为一等公民

👉 defer 机制基础

这些内容,是拉开 Go 水平差距的关键


匿名函数(Anonymous Function)

什么是匿名函数?

👉 没有函数名的函数

go 复制代码
func() {
    fmt.Println("hello")
}

立即执行函数(IIFE)

go 复制代码
package main

import "fmt"

func main() {
	func() {
		fmt.Println("hello world")
	}()
}

输出:

bath 复制代码
Hello, World!

👉 特点:

  • 定义后立即执行
  • 常用于临时逻辑

匿名函数赋值给变量

go 复制代码
package main

import "fmt"

func main() {
	add := func(a, b int) int {
		return a + b
	}

	fmt.Println(add(10, 20))
}

输出:

bath 复制代码
30

👉 本质:

  • 函数可以像变量一样使用

函数是一等公民(重点理解)

在 Go 中,函数可以:

  • 赋值给变量 ✅
  • 作为参数传递 ✅
  • 作为返回值返回 ✅

👉 这就是"函数式编程"的基础


函数作为参数

go 复制代码
package main

import "fmt"

// 这里演示了如何使用函数作为参数传递
func calc(a, b int, op func(int, int) int) int {
	return op(a, b)
}
func add(a, b int) int {
	return a + b
}
func main() {
	res := calc(10, 20, add)
	fmt.Println(res)
	fmt.Println(add(2, 3))
}

输出:

bath 复制代码
30
5

👉 使用匿名函数:

go 复制代码
package main

import "fmt"

func calc(a, b int, op func(int, int) int) int {
	return op(a, b)
}
// 匿名函数作为参数传递
func main() {
	res := calc(10, 20, func(a, b int) int {
		return a * b
	})
	fmt.Println(res)
}

输出:

bath 复制代码
200

📌 使用场景:

  • 策略模式
  • 回调函数
  • 中间件设计

函数作为返回值

go 复制代码
package main

import "fmt"

func choose(op string) func(int, int) int {
	if op == "+" {
		return func(a, b int) int {
			return a + b
		}
	}
	if op == "-" {
		return func(a, b int) int {
			return a - b
		}
	}
	// 就是没有匹配上+ - 这两个操作符,就直接a,b 直接返回a和b数值即可
	return func(a, b int) int {
		fmt.Println("没有匹配到操作符")
		fmt.Println(a, b)
		return 0
	}

}
func main() {
	f := choose("*")
	fmt.Println(f(10, 5))
}

输出:

bath 复制代码
没有匹配到操作符
10 5
0

👉 场景:

  • 工厂模式
  • 动态逻辑选择

闭包(Closure)🔥面试重点

什么是闭包?

👉 函数 + 外部变量 = 闭包


示例:计数器

go 复制代码
package main

import "fmt"

func counter() func() int {
	i := 0
	return func() int {
		i++
		return i
	}
}
func add(a int) int {
	i := a
	i++
	return i
}
func main() {
	c := counter()
	fmt.Println(c()) // 1
	fmt.Println(c()) // 2
	fmt.Println(c()) // 3
	// 下边这个是作对比的
	fmt.Println(add(5))
	fmt.Println(add(6))
	fmt.Println(add(7))
}

输出:

bath 复制代码
1
2
3
6
7
8

为什么能"记住变量"?

👉 因为:

  • i 并没有被销毁
  • 被内部函数"引用"住了
  • 生命周期被延长

📌 本质理解:

闭包 = 捕获外部变量的函数


闭包的实际应用

状态保存

go 复制代码
package main

import "fmt"

func accumulator(base int) func(int) int {
	return func(x int) int {
		base += x
		return base
	}
}
func main() {
	acc := accumulator(10)
	fmt.Println(acc(5)) // 输出: 15
	fmt.Println(acc(3)) // 输出: 18
	fmt.Println(acc(2)) // 输出: 20
}

权限/配置封装

👉 在中间件、限流器中非常常见


defer 机制基础(必考🔥)

defer 是什么?

👉 用于"延迟执行"

go 复制代码
package main

import (
	"fmt"
	"time"
)

func main() {
	fmt.Println(time.Now().Format("2006-01-02 15:04:05.0000000"))
	defer fmt.Println("world")
	fmt.Println("hello")
	fmt.Println(time.Now().Format("2006-01-02 15:04:05.0000000"))
}

输出:

bath 复制代码
2026-04-13 22:13:34.0237855
hello
2026-04-13 22:13:34.0240836
world

多个 defer 执行顺序

go 复制代码
package main

import (
	"fmt"
)

func main() {
	defer fmt.Println(1)
	defer fmt.Println(2)
	defer fmt.Println(3)
}

输出:

bath 复制代码
3
2
1

👉 结论:

  • defer 是后进先出(栈)

defer 常见使用场景

📌 资源释放

go 复制代码
file, _ := os.Open("test.txt")
defer file.Close()

📌 解锁

go 复制代码
mu.Lock()
defer mu.Unlock()

👉 优点:

  • 防止忘记释放资源
  • 代码更安全

小结(建议收藏⭐)

这一篇,我们掌握了 Go 函数的核心进阶能力:

✅ 匿名函数(立即执行 / 赋值)

✅ 函数是一等公民(参数 / 返回值)

✅ 闭包(核心重点🔥)

✅ defer 延迟执行机制

✅ 常见使用场景(资源释放 / 回调 / 封装逻辑)


🎯 最后说一句

如果说第一篇是"基础",那这一篇就是:

👉 真正进入 Go 编程思维的关键

因为:

  • 闭包 → 用于封装状态
  • 函数传递 → 用于解耦逻辑
  • defer → 用于资源管理

这些都是写工程代码必须掌握的能力


🚀 下一篇预告(强烈建议继续看)

👉 深入理解 Go 函数(下):defer 执行时机、值传递陷阱与经典面试坑

会带你解决:

  • defer 为什么有时候"坑你"
  • range + 闭包为什么会出 bug
  • slice / map 传参到底怎么回事

相关推荐
飞Link2 小时前
LangGraph SDK 全量技术手册:分布式 Agent 集群的远程调用与编排引擎
开发语言·分布式·python·数据挖掘
itzixiao2 小时前
L1-041 寻找250(10分)
开发语言
njsgcs2 小时前
获得solidworks 3d零件的包围框 长宽高 boundingbox c#
开发语言·c#·solidworks
网域小星球2 小时前
C 语言从 0 入门(十九)|共用体与枚举:自定义类型进阶
c语言·开发语言·算法·枚举·自定义类型·共用体
Evand J2 小时前
【滤波代码介绍|MATLAB】粒子滤波(PF)与自适应粒子滤波(APF)在三维动态系统状态估计中的对比,使用Sage Husa自适应的思想
开发语言·matlab·pf·粒子滤波·apf·自适应滤波
zybsjn2 小时前
异步并发的“流量警察”:在C#中使用SemaphoreSlim进行并发控制的最佳实践
开发语言·c#
Cx330❀2 小时前
线程进阶实战:资源划分与线程控制核心指南
java·大数据·linux·运维·服务器·开发语言·搜索引擎
人道领域2 小时前
【黑马点评日记02】:Session+ThreadLocal实现短信登录
java·开发语言·spring·tomcat·intellij-idea
广州灵眸科技有限公司2 小时前
瑞芯微(EASY EAI)RV1126B 系统操作-线进程操作
开发语言·科技·嵌入式硬件·物联网