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

 

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