代码:
package main
import "fmt"
func add() func(int) int {
sum:=0
innerFunc := func(x int) int{
sum += x
return sum
}
return innerFunc
}
func main() {
pos, neg := add(), add()
for i:=0;i<5;i++{
fmt.Println(pos(i),neg(-1*i))
}
}
预期结果:
0 0
1 -1
2 -2
3 -3
4 -4
实际输出:
0 0
1 -1
3 -3
6 -6
10 -10
问:为啥局部变量sum值会有变化呢?
答:该问题其实牵涉到一种编程模式——函数式编程,在golang中主要体现在闭包应用上面。
何为函数式编程呢?我们中的大多数人可能都学习过面向过程编程和面向对象编程,但对函数式编程并太不了解。函数式编程其实是需要一定的条件的,那就是函数被认定为“一等公民”和语言支持匿名函数。
何为“一等公民”?“一等公民”意味着函数可以像普通的类型(整型、字符串等)一样进行赋值、作为函数的参数传递、作为函数的返回值等。支持函数为“一等公民的”常见编程语言有:Golang、Python、Scala、JavaScript、Ruby等。
关于函数式编程思想,有一本书叫《Learning Functional Programming in Go》,作者Lex Sheehan,有兴趣可以下载。百度云链接:https://pan.baidu.com/s/1VKTyKX_Vyhb2sVC9PFzqzQ 密码:ylc3
其实我们通常谈论到的函数式编程是关于闭包的。网上已经有很多关于闭包的讲解,附上一个我觉得不错的地址https://www.ibm.com/developerworks/cn/linux/l-cn-closure/index.html
那么本例中,闭包环境为
func add() func(int) int {
sum:=0
innerFunc := func(x int) int{
sum += x
return sum
}
return innerFunc
}
目前我的理解:
匿名函数和它引用的变量以及环境,类似常规函数引用全局变量处于一个包的环境。
可以将innerFunc代表的匿名函数看作常规函数,而sum就看作全局变量,它们都存在于add(),innerFunc不仅仅是存储了一个函数的返回值,它同时存储了一个闭包的状态。在匿名函数中操作sum,那么就相当于在常规函数中操作全局变量。因此,当本例中的pos和neg分别代表add()的实例化对象时,它们的每次执行,其函数空间中的sum值都会跟随执行被改变。
一、业务函数的计数器
代码:
package main
import "fmt"
func countFun(f func()) func() int{
count :=0
a := func () int{
f()
count++
fmt.Printf("work() had do %d times work\n",count)
return count
}
return a
}
func work() {
println("working...")
}
func main() {
cf := countFun(work)
for i:=0;i<5;i++{
cf()
}
}
输出:
working...
work() had do 1 times work
working...
work() had do 2 times work
working...
work() had do 3 times work
working...
work() had do 4 times work
working...
work() had do 5 times work
二、实现装饰器(装饰器模式简要来讲就是保证已有方法完整性的前提下,提供额外的功能)
代码:
package main
import "fmt"
func wrapper(f func() string) {
fmt.Println("ready...")
fmt.Println(f())
fmt.Println("end")
}
func workerOne() string {
return "worker one work!"
}
func workerTwo() string {
return "worker two work!"
}
func main() {
wrapper(workerOne)
wrapper(workerTwo)
}
输出:
ready...
worker one work!
end
ready...
worker two work!
end
三、实现斐波那契数列(在数学上,斐波那契数列以如下被以递归的方法定义:F0=0,F1=1,Fn=Fn-1+Fn-2(n>=2,n∈N*))
代码:
package main
import "fmt"
func makeFibGen() func() int {
a := 0
b := 1
return func() int {
b, a = a+b, b
return a
}
}
func main() {
gen := makeFibGen()
for i := 0; i < 10; i++ {
fmt.Println(gen())
}
}
输出:
1
1
2
3
5
8
13
21
34
55