Go匿名函数须用func关键字声明,参数和返回类型不可省略;是表达式,需赋值或显式调用;闭包捕获变量引用而非值,循环中直接捕获i会导致所有函数共享同一变量。

Go 里匿名函数的定义语法
Go 中匿名函数必须用 func 关键字声明,不能省略参数列表和返回类型,即使为空也要写成 func() 或 func() int。它不是“变量赋值即函数”,而是表达式,必须显式调用或赋给变量才能使用。
常见错误是漏掉括号或类型声明,比如写成 var f = func { ... }(缺参数列表)或 func() { ... }()(没赋值就直接调用但上下文不支持)。
- 正确写法:赋给变量后调用
var greet = func(name string) { fmt.Println("Hello", name) } greet("Alice") - 立即执行:需加括号包裹整个函数字面量
(func(x, y int) int { return x + y })(3, 4) - 返回函数时,返回类型必须明确声明为函数签名,如
func() string
闭包捕获变量的注意事项
Go 匿名函数形成闭包时,捕获的是变量的引用,不是快照。在循环中直接捕获循环变量容易导致所有函数共享同一个变量实例。
典型问题代码:
for i := 0; i < 3; i++ {
defer func() { fmt.Println(i) }() // 全部输出 3
}
- 修复方式:传参进匿名函数,让每次迭代绑定当前值
for i := 0; i < 3; i++ { defer func(val int) { fmt.Println(val) }(i) } - 或在循环内用新变量接收
for i := 0; i < 3; i++ { i := i // 创建新绑定 defer func() { fmt.Println(i) }() } - 注意:闭包捕获的变量生命周期会延长,直到匿名函数不再被引用
常用于 goroutine 和 defer 的场景
匿名函数在并发和延迟执行中高频出现,因为能自然携带上下文数据,避免全局或额外结构体封装。
立即学习“go语言免费学习笔记(深入)”;
- 启动 goroutine 时传参更清晰:
go func(url string) { resp, _ := http.Get(url) defer resp.Body.Close() }(url) -
defer配合匿名函数做资源清理,比单独写函数更轻量:file, _ := os.Open("data.txt") defer func(f *os.File) { if f != nil { f.Close() } }(file) - 注意:goroutine 中若需长时间持有变量,要确认是否意外延长了内存生命周期
作为函数参数传递时的类型匹配
Go 是强类型语言,匿名函数传参必须严格匹配目标形参的函数类型。哪怕逻辑一致,func(int) string 和 func(int) string 看似一样,但如果定义在不同包或有别名,也可能不兼容。
- 常见错误:把匿名函数直接传给期望
http.HandlerFunc的接口,却忘了它本质是func(http.ResponseWriter, *http.Request)类型 - 正确写法:
http.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("ok")) }) - 如果函数体复杂,建议先定义具名函数再传入,提升可读性和复用性;匿名函数适合逻辑简单、作用域明确的一次性行为










