golang爬坑笔记之自问自答系列(2)——函数式编程(闭包)

代码:

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章