函数式编程
正统的函数式编程有两个要求:
- 不可变性:只能有常量和函数。
- 函数只能有一个参数
go语言中的函数式编程显然不是正统的函数式编程,因为go语言的函数大都包含了变量和多个参数。
函数式编程实现的前提条件
函数式编程顾名思义,以函数为中心进行编程,意味着函数可以当作变量进行赋值,可以当作另外一个函数的入参,可以作为返回值返回。综合起来,函数式编程要将函数视为一级对象。
go语言实现函数式编程
go语言通过闭包实现函数式编程,而闭包的价值在于可以作为函数对象或者匿名函数。闭包的概念为闭包是包含自由变量的代码块,自由变量指的是没有在代码块内定义,而是在定义代码块的环境中定义,因为这些代码块运行的时候引用了自由变量,因此自由变量不会被垃圾回收器回收,而是一直存在。
上代码解释:
package main
import "fmt"
func adder() func(int) int {
sum := 0
return func(i int) int {
sum += i
return sum
}
}
func main() {
add := adder()
for i := 0; i < 10; i++ {
fmt.Printf("0 + .... + %d: %d\n", i, add(i))
}
}
首先定义adder()函数,adder()函数没有入参,返回体为一个匿名函数,这个匿名函数就是闭包。匿名函数传入局部变量i,同时拥有一个外部的sum,而这个sum就是自由变量,因为sum没有在匿名函数这个代码块内部被定义,而是在外部被定义,而这个外部就是定义代码块的环境,根据闭包的定义,这个匿名函数就是一个闭包,而返回的闭包内部除了具体的运输代码,局部变量i,还有就是自由变量sum,由于自由变量被闭包调用,因此当函数运行的时候,sum不会被回收,它会一直被累加,而产生的结果如下。
0 + .... + 0: 0
0 + .... + 1: 1
0 + .... + 2: 3
0 + .... + 3: 6
0 + .... + 4: 10
0 + .... + 5: 15
0 + .... + 6: 21
0 + .... + 7: 28
0 + .... + 8: 36
0 + .... + 9: 45
闭包的主体为函数体,函数体包含局部变量和自由变量,如果自由变量是结构的话,还包含结构连接的其它结构。
用自由变量sum进行累加,这当然非常灵活,但从正统的函数式编程来说,它显然不是,因为sum是一个变量,如果用变量来表示一个可变的状态的话,它就不是一个正统的函数式编程,正统的函数式编程只能是常量和函数,因此我们可以用函数来表示状态,实现累加的效果,代码如下:
type Addr func(int) (int, Addr)
func getResultAndState(v int) Addr {
return func(i2 int) (i int, addr Addr) {
return v + i2, getResultAndState(v + i2)
}
}
func main() {
add := getResultAndState(0)
for i := 0; i < 10; i++ {
var i2 int
i2, add = add(i)
fmt.Printf("0 + .... + %d: %d\n", i, i2)
}
}
首先定义函数结构体,入参为int变量,返回值为其本身和结果,这样可以用该函数存储状态。定义函数getResultAndState,函数的返回值为闭包,这个闭包包含了结果和下一个状态函数。