匿名函数与闭包
匿名函数
匿名函数是指不需要定义函数名的一种函数实现方式。在Go里面里面可以像普通变量一样被传递或使用,Go语言支持在随时代码块中定义匿名函数。
匿名函数由一个不带函数名的函数声明和函数体组成,如下所示:
func (a, b int, z float64) bool {
return a*b < int(z)
}
匿名函数可以直接赋值给一个变量或者直接执行,当然也能够作为另一个函数的返回值使用:
f := func(x, y int) int {
return x+y
}
func (ch chan int) {
ch <- ACK
} (reply_chan)
花括号之后直接跟参数列表表示函数调用
闭包
- 基本概念
闭包可以包含自由(未绑定到特定对象)变量的代码块,这些变量不会在这个代码块内或者是任何全局上下文中定义,而是在定义代码块的环境中定义。要执行的代码为自由变量提供绑定的计算环境(作用域)。
- 闭包的价值
闭包的价值在于可以作为函数对象或者匿名函数,对于类型系统而言,这意味着不但要表示数据还要表示代码。意味着这些函数可以储存到变量中作为参数传递给其他函数,最重要的是能够被函数动态的创建和返回。
- Go语言中的闭包
Go 语言支持匿名函数,可作为闭包。匿名函数是一个”内联”语句或表达式。匿名函数的优越性在于可以直接使用函数内的变量,不必申明。
以下实例中,我们创建了函数 getSequence() ,返回另外一个函数。该函数的目的是在闭包中递增 i 变量,代码如下:
package main
import (
"fmt"
)
func getSequence() func() int {
i := 0
return func() int {
i++
return i
}
}
func main() {
nextNumber1 := getSequence()
fmt.Println(nextNumber1())
fmt.Println(nextNumber1())
fmt.Println(nextNumber1())
nextNumber2 := getSequence()
fmt.Println(nextNumber2())
fmt.Println(nextNumber2())
}
试想,若是变量 i 定义在这个代码块内(就如同我们常见的一个函数内部定义的局部变量),那么每次函数调用完成后,局部变量的生命周期随之结束,我们看到的运行结果一定是:
1
1
1
1
1
若是这个变量 i 是定于在全局上下文中(我理解就是全局变量),那么这个函数被调用5次的输出一定是:
1
2
3
4
5
但实际上,运行结果:
1
2
3
1
2
在上面这个示例中,变量nextNumber1 和 nextNumber2 均指向了闭包函数,其数据是完全隔离的,他们都有各自独立的自由 i ,这就是在定义代码块的环境中定义的意思。只要变量nextNumber1 和 nextNumber2 还存在,自由变量 i 就不会被释放掉。
闭包函数内的局部变量 i 无法通过其他途径进行访问和修改,这保证了 i 的安全性。