爱上开源之golang入门至实战第四章函数(Func)(六)
4.4.6 匿名函数和闭包
Go语言支持匿名函数,在前面就讲到过,在Go语言里,函数更像是定义的一个函数类型的对象;在Go语言里,匿名函数更复合这个特性;匿名函数可以在需要使用函数时再定义函数,匿名函数没有函数名只有函数体,这样GO语言的匿名函数作为一种类型被赋值给函数类型的变量,匿名函数也往往以变量方式传递,这与C语言的回调函数比较类似,不同的是,Go语言支持随时在代码里定义匿名函数。 下面来具体介绍一下匿名函数的定义及使用。
匿名函数是指不需要定义函数名的一种函数实现方式,由一个不带函数名的函数声明和函数体组成。
func(参数列表)(返回参数列表){
函数体
}
fn := func(x int) int {
return x * x
}
fmt.Printf("Result = %d \n", fn(3))
==== OUTPUT ====
Result = 9
上面的例子就是一个简单的匿名函数的示例,示例里通过 func(x int) int, 定义了一个参数类型是
int,返回值是int的匿名函数;函数体实现了返回参数的平方的结果;然后将匿名函数定义的变量赋
匿名函数也被称闭包函数(函数式语言的术语),它们被允许调用定义在其它环境下的变量。闭包
可使得某个函数捕捉到一些外部状态,
例如:函数被创建时的状态。另一种表示方式为:一个闭包继承了 函数所声明时的作用域。这种
状态(作用域内的变量)都被共享到闭包的环境中,因此这些变量可以在闭包中被操作,直到被销
毁。闭包经常被用作包装函数:它们会预先定义好 1 个或多个参数以用于包装。另一个不错的应用
就是使用闭包来完成更加简洁的错误检查。 仅仅从形式上将闭包简单理解为匿名函数是不够的,
还需要理解闭包;实质上的含义。 实质上看,闭包是由函数及其相关引用环境组合而成的实体
(即:闭包=函数+引用
环境)。闭包在运行时 可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。
由闭包的实质含义,可以判断出,闭
包获取捕获变量相当于引用传递,而非值传递;对于闭包函数捕获的常量和变量,无论闭包何时何
处被调用,闭包都可以使用这些常量和
变量,而不用关心它们表面上的作用域。利用匿名函数(闭包函数)的这些作用域特性去实现一些
功能,就是编程技巧的一种体现。看看下面的示例:
func TestAnonymous2(t *testing.T) {
for idx := 0; idx < 10; idx++ {
fn := func() int {
return idx * idx
}
fmt.Printf("Result(%d*%d) = %d \n", idx, idx, fn())
}
}
==== OUTPUT ====
Result(0*0) = 0
Result(1*1) = 1
Result(2*2) = 4
Result(3*3) = 9
Result(4*4) = 16
Result(5*5) = 25
Result(6*6) = 36
Result(7*7) = 49
Result(8*8) = 64
Result(9*9) = 81
上面的例子,匿名函数就是用了作用域内的变量idx; 对于闭包函数捕获的常量和变量,无论闭包何时何处被调用,闭包都可以使用这些常量和变量,而不用关心它们表面上的作用域。
把上面的例子,改一改,看看匿名函数对作用域的变量idx的修改会有什么样的影响
func TestAnonymous2(t *testing.T) {
for idx := 0; idx < 10; {
fn := func() (rtn int) {
rtn = idx * idx
idx++
return
}
fmt.Printf("Result(%d*%d) = %d \n", idx, idx, fn())
}
}
==== OUTPUT ====
Result(1*1) = 0
Result(2*2) = 1
Result(3*3) = 4
Result(4*4) = 9
Result(5*5) = 16
Result(6*6) = 25
Result(7*7) = 36
Result(8*8) = 49
Result(9*9) = 64
Result(10*10) = 81
由这段代码以判断出,闭包获取捕获变量相当于直接引用了变量, 对变量的任何修改都直接修改变量;类似于引用传递的效果,而非
值传递。
func TestAnonymous3(t *testing.T) {
var fn func(x uint8) []uint8
fn = func(x uint8) (rtn []uint8) {
if x == 0 {
rtn = append(rtn, 0)
return
}
if x == 1 {
rtn = append(rtn, 0, 1)
return
}
if x == 2 {
rtn = append(rtn, 0, 1, 1)
return
}
rtn = append(fn(x - 1))
rtn = append(rtn, rtn[len(rtn)-1]+rtn[len(rtn)-2])
return
}
fmt.Printf("Result(%d) = %v \n", 10, fn(10))
}
==== OUTPUT ====
Result(10) = [0 1 1 2 3 5 8 13 21 34 55]