引入
有时候一段逻辑只用一次,没必要起个名字声明成独立函数。Go 允许把函数当值来用——赋给变量、当参数传递、从函数里返回,还能通过闭包”记住”外部变量。这些特性让代码更灵活,尤其在处理回调和延迟执行时。
正文
定义
定义
匿名函数是没有名字的函数,可以直接赋值给变量或立即执行。闭包是匿名函数引用了外部变量的状态,使得函数可以”记住”创建时的环境。Go 里函数是一等公民,可以作为值传递和作为参数接收。
语法
// 匿名函数赋值给变量
add := func(a, b int) int {
return a + b
}
// 立即执行的匿名函数
result := func(a, b int) int {
return a + b
}(3, 4)
// 闭包:函数引用外部变量
func counter() func() int {
count := 0
return func() int {
count++
return count
}
}
// 函数作为参数(回调)
func apply(fn func(int) int, x int) int {
return fn(x)
}例子
匿名函数赋值
greet := func(name string) {
fmt.Println("Hello,", name)
}
greet("Alice")把匿名函数赋给变量,通过变量名调用,和普通函数用起来一样。
立即执行匿名函数
result := func(a, b int) int {
return a + b
}(3, 5)
fmt.Println(result) // 8定义完直接传参执行,适合只需要运行一次的逻辑。
闭包
func makeCounter() func() int {
count := 0
return func() int {
count++
return count
}
}
func main() {
c := makeCounter()
fmt.Println(c()) // 1
fmt.Println(c()) // 2
fmt.Println(c()) // 3
}闭包捕获了外部变量 count,每次调用 c() 都修改同一个 count,函数之间共享状态。
多个闭包共享变量
func makeCounter() (func() int, func() int) {
count := 0
inc := func() int {
count++
return count
}
dec := func() int {
count--
return count
}
return inc, dec
}
func main() {
inc, dec := makeCounter()
fmt.Println(inc()) // 1
fmt.Println(inc()) // 2
fmt.Println(dec()) // 1
}两个闭包共享同一个 count,一个负责加,一个负责减。
函数作为参数
func double(n int) int {
return n * 2
}
func apply(fn func(int) int, x int) int {
return fn(x)
}
func main() {
result := apply(double, 5)
fmt.Println(result) // 10
}把函数当参数传进去,apply 不关心具体逻辑,只负责调用。
函数作为返回值
func multiplier(factor int) func(int) int {
return func(n int) int {
return n * factor
}
}
func main() {
triple := multiplier(3)
fmt.Println(triple(5)) // 15
}multiplier 返回一个新函数,这个函数”记住”了 factor 的值。
回调模式
func fetchData(url string, onSuccess func(string), onError func(error)) {
// 模拟请求
data := "response data"
if data != "" {
onSuccess(data)
} else {
onError(errors.New("请求失败"))
}
}
func main() {
fetchData("https://example.com",
func(data string) {
fmt.Println("成功:", data)
},
func(err error) {
fmt.Println("失败:", err)
},
)
}回调就是把函数传给另一个函数,让它在合适的时机调用,常见于异步处理和事件驱动。
常见写法
| 写法 | 说明 |
|---|---|
fn := func() {} | 匿名函数赋值给变量 |
func() {}() | 立即执行匿名函数 |
func outer() func() int { … } | 返回闭包 |
func apply(fn func(int) int, x int) | 函数作为参数 |
fn := multiplier(3) | 函数作为返回值 |
onSuccess(data) | 回调模式 |
特点
- Go 里函数是一等公民,可以赋值、传参、返回
- 闭包捕获外部变量的引用,不是值的副本,多次调用共享状态
- 匿名函数常用于
defer、goroutine和回调场景 - 闭包的变量生命周期超出外部函数,只要闭包还在用就不会被回收
- 函数类型可以作为参数类型声明:
func(int) int - 回调模式在 Go 里不如 JavaScript 常见,Go 更倾向用 channel 和 interface
理解
匿名函数和闭包让函数不再只是”被调用”,而是变成了可以传递和组合的数据。闭包最强大的地方是能记住外部状态,适合做计数器、工厂、延迟计算等场景。不过要注意闭包捕获的是引用,在循环里用闭包容易踩坑。
引出
函数作为参数传递已经很灵活了,Go 还支持一种特殊的参数形式——数量不定的参数。接下来看 Go 可变参数 怎么用 … 接收任意多个参数。