golang匿名函数的活用
回调函数
package main
import "fmt"
type FuncType func(int, int) int
// Calc 计算函数
func Calc(a, b int, fTest FuncType) (result int) {
result = fTest(a, b)
return
}
func main() {
x, y := 2, 2
// Add
// 回调函数是匿名函数
addResult := Calc(x, y, func(a int, b int) int {
return a + b
})
// 回调函数是匿名函数
subResult := Calc(x, y, func(a int, b int) int {
return a - b
})
fmt.Println("addResult: ", addResult)
fmt.Println("subResult: ", subResult)
}
运行结果:
addResult: 4
subResult: 0
闭包
我们使用一个特殊的情况来举例子,顺便巩固一下并发的知识。
请看以下代码,是golang并发中的闭包:
package main
import (
"fmt"
"runtime"
"sync"
)
func main() {
runtime.GOMAXPROCS(runtime.NumCPU())
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
fmt.Println(i)
wg.Done()
}()
}
wg.Wait()
}
运行结果:
5
5
5
5
5
造成这一输出结果的原因是启动一个goroutine的时间慢于主goroutine中循环的执行时间。
这个时候你可能会想到使用循环延时的办法,但是一旦这样做,就失去了并发优势。
所以一般采用以下两个方法:
-
将循环变量作为参数传递给匿名函数,原因在于传参的速度几乎是瞬时的,且在启动goroutine前执行。
for i := 0; i < 5; i++ { wg.Add(1) go func(i int) { fmt.Println(i) wg.Done() }(i) } // 4 // 2 // 3 // 0 // 1
-
使用同名变量保留当前循环变量的状态
for i := 0; i < 5; i++ { wg.Add(1) i := i go func() { fmt.Println(i) wg.Done() }() } // 0 // 1 // 3 // 4 // 2
其它用法
定义时调用匿名函数
func sayHi() {
func() {
fmt.Println("hello")
}()
}
func main() {
sayHi()
}
将匿名函数复制给变量
func main() {
var sayHi func() = func() {
fmt.Println("hello")
}
sayHi()
}
带有return的匿名函数
func sayHi() {
greet := func() string {
return "hello"
}
fmt.Println(greet())
}
func main() {
sayHi()
}
遍历对象数组时做一些回调操作
在学习godis的时候,其中有一个数据引擎接口:EmbedDB
。里面有一个遍历当前数据库所有内容的函数:forEach
,该函数的形参列表中有一个匿名函数,可以在函数调用的时候,做一些回调操作,我觉得很巧妙。于是就有了下面的例子,该例子没有任何意义,仅仅是展现匿名函数的该种用法。
package main
import "fmt"
type function interface {
forEach(func(i int))
}
// Array 数组结构体实现了接口
type Array struct {
array []int
length int
}
func (a *Array) forEach(callBack func(i int)) {
for i := 0; i < a.length; i++ {
callBack(i)
}
}
func (a *Array) Add(value int) {
a.array = append(a.array, value)
a.length++
}
func NewArray() Array {
return Array{
make([]int, 0),
0,
}
}
func main() {
arr := NewArray()
arr.Add(1)
arr.Add(2)
arr.Add(3)
// 将每个元素++
arr.forEach(func(i int) {
arr.array[i]++
})
// 打印每个元素
arr.forEach(func(i int) {
fmt.Println(arr.array[i])
})
}
输出结果:
2
3
4