Go 语言三大进阶函数技巧
【摘要】 初学 Go 时,我们常写这样的函数:func add(a int, b int) int { return a + b}但真实项目中,函数远不止“传参返值”这么简单。今天分享 3 个高频实用的进阶技巧——让函数更灵活、更安全、更专业 👇 1️⃣ 技巧一:变长参数(Variadic Functions)✅ 场景:日志打印、求和、批量操作 🌰 传统写法(硬编码参数个数)func sum...
初学 Go 时,我们常写这样的函数:
func add(a int, b int) int {
return a + b
}
但真实项目中,函数远不止“传参返值”这么简单。
今天分享 3 个高频实用的进阶技巧——让函数更灵活、更安全、更专业 👇
1️⃣ 技巧一:变长参数(Variadic Functions)
✅ 场景:日志打印、求和、批量操作
🌰 传统写法(硬编码参数个数)
func sum2(a, b int) int { return a + b }
func sum3(a, b, c int) int { return a + b + c }
// ❌ 需要写 N 个函数?
✅ 进阶写法:...T 变长参数
// 接收任意数量的 int 参数
func sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
// 使用
fmt.Println(sum(1, 2)) // → 3
fmt.Println(sum(1, 2, 3, 4)) // → 10
fmt.Println(sum()) // → 0(空参数合法!)
⚠️ 注意事项
| 陷阱 | 正确做法 |
|---|---|
... 只能在最后一个参数使用 |
func bad(a ...int, b int) ❌ |
传入切片需加 ... 解包 |
nums := []int{1,2,3}; sum(nums...) ✅ |
空调用安全,nums 为 []int{} 而非 nil |
可放心 range |
▲ ...int 本质是 []int,但语法糖让调用更自然
2️⃣ 技巧二:函数作为参数(First-Class Functions)
✅ 场景:回调、策略模式、中间件、测试 Mock
Go 中函数是一等公民——可赋值、传参、返回。
🌰 案例:通用遍历 + 自定义操作
// 定义函数类型(可读性更强)
type Transformer func(int) int
// 接收函数作为参数
func apply(numbers []int, fn Transformer) []int {
result := make([]int, len(numbers))
for i, v := range numbers {
result[i] = fn(v)
}
return result
}
// 使用
nums := []int{1, 2, 3, 4}
double := func(x int) int { return x * 2 }
square := func(x int) int { return x * x }
fmt.Println(apply(nums, double)) // → [2 4 6 8]
fmt.Println(apply(nums, square)) // → [1 4 9 16]
✅ 实战:实现 filter 和 map
// 过滤器:保留偶数
func filter(nums []int, predicate func(int) bool) []int {
var res []int
for _, n := range nums {
if predicate(n) {
res = append(res, n)
}
}
return res
}
// 使用
evens := filter([]int{1,2,3,4,5}, func(n int) bool {
return n%2 == 0
})
fmt.Println(evens) // → [2 4]
💡 优势:
- 逻辑复用(
apply/filter可用于任何类型) - 行为注入(无需修改函数体即可改变策略)
3️⃣ 技巧三:闭包(Closure)捕获变量
✅ 场景:配置化函数、计数器、延迟计算、工厂模式
闭包 = 函数 + 自由变量环境
🌰 案例:生成带“记忆”的计数器
// 返回一个闭包:每次调用自增
func newCounter() func() int {
count := 0 // 自由变量:被闭包捕获
return func() int {
count++ // 修改捕获的变量
return count
}
}
// 使用
c1 := newCounter()
c2 := newCounter()
fmt.Println(c1()) // → 1
fmt.Println(c1()) // → 2(记住上次状态!)
fmt.Println(c2()) // → 1(独立状态)
🛠️ 实战:HTTP 中间件骨架
func authMiddleware(requiredRole string) func(http.HandlerFunc) http.HandlerFunc {
return func(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
userRole := r.Header.Get("X-Role")
if userRole != requiredRole {
http.Error(w, "Forbidden", http.StatusForbidden)
return
}
next(w, r) // 继续执行
}
}
}
// 使用
http.HandleFunc("/admin",
authMiddleware("admin")(adminHandler),
)
⚠️ 闭包常见坑:循环变量陷阱
// ❌ 错误:所有函数共享同一个 i(=3)
funcs := make([]func(), 3)
for i := 0; i < 3; i++ {
funcs[i] = func() { fmt.Println(i) }
}
funcs[0]() // → 3 ❌
// ✅ 修复:用参数“固化”当前值
for i := 0; i < 3; i++ {
i := i // 创建新变量(Go 1.22+ 可省略)
funcs[i] = func() { fmt.Println(i) }
}
funcs[0]() // → 0 ✅
▲ 闭包函数持有对 count 的引用,生命周期延长
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)