一.函数式编程 VS 函数指针
- 函数是go语言中的一等公民,参数 变量 返回值都可以是函数
- go语言并不是正统的函数式编程,go语言的函数式编程主要体现在 "闭包" 上
- 高阶函数
- 关于"闭包"的理解:阮一峰_学习Javascript闭包(Closure) 廖雪峰_javascript闭包 Golang-函数式编程(闭包)
注:正统的函数式编程:
- 不可变性:不能有状态,只有常量和函数
- 函数只能有一个参数
二.闭包
函数可以嵌套定义,即在一个函数内部可以定义另一个函数,有了嵌套函数这种结构,便会产生闭包问题.Go不能在函数内部显式嵌套定义函数,但是可以定义一个匿名函数.
理解闭包最方便的方法就是将闭包函数看成一个类,一个闭包函数调用就是实例化一个类,然后就可以从类的角度看出哪些是“全局变量”,哪些是“局部变量”。
通过闭包实现累加和
func adder() func (value int) int{
sum := 0
return func (v int) int{ //返回的匿名函数就是一个闭包,对于闭包,v是局部变量,sum是自由变量,是闭包所处的环境
sum += v
return sum
}
}func main() {
a1 := adder() //a是adder()返回的匿名函数,就是闭包
a2 := adder()
for i:= 0; i < 5; i++{
fmt.Printf("0+...+%d=%d\n", i,a1(i))
}
for i:= 0; i < 5; i++{
fmt.Printf("0+...+%d=%d\n", i,a2(i))
}
}
结果:
0+...+0=0
0+...+1=1
0+...+2=3
0+...+3=6
0+...+4=10
0+...+0=0
0+...+1=1
0+...+2=3
0+...+3=6
0+...+4=10
在上述例子中函数adder()内部定义了一个匿名函数,并将这个匿名函数作为返回值,这个匿名函数就是闭包.匿名函数可以定义自己的变量 v,但同时也可以访问adder()内定义的变量 sum ,对于匿名函数来说,它自己定义的变量 v,是属于它的局部变量,而它可以访问的 sum 就是它的全局变量,也就是它所处环境中的变量,我们一般称作"自由变量".
上述例子中,可以看到两次调用adder()产生的结果 a1, a2 是隔离的.在实际操作中,每次调用adder()函数,都会分配一个 sum, 同时返回一个可以访问操作 sum 的匿名函数(闭包).其实,调用adder(), 可以理解为实例化了一个"闭包类",在这个实例化的"闭包类"中,有数据域 sum ,和对数据域的操作函数(闭包).
套用一句经典的话,对象是附有行为的数据,而闭包是附有数据的行为。
三.函数式编程例子
1> 斐波那契数列
//0 1 1 2 3 5 8 13
//a b
// a b
// a b
func fibonacci () func () int{
a, b := 0, 1
return func () int {
a, b = b, a+b
return a
}
}func main(){
f := fibonacci()
for i := 0; i<10; i++{
fmt.Printf("%d ",f())
}
}结果:1 1 2 3 5 8 13 21 34 55
2> 为函数实现接口
func fibonacci () intGen{
a, b := 0, 1
return func () int {
a, b = b, a+b
return a
}
}type intGen func() int //为闭包创建一个类型,为其实现 io.Reader 接口
func (g intGen) Read(p []byte) (n int, err error){
next := g()
if next > 1000 {
return 0, io.EOF
}
s := fmt.Sprintf("%d\n", next)
return strings.NewReader(s).Read(p)
}func readFileContents(r io.Reader){
scanner := bufio.NewScanner(r)
for scanner.Scan(){
fmt.Println(scanner.Text())
}
}func main(){
f := fibonacci()
readFileContents(f)
}
3> 使用函数遍历二叉树
type node struct{
data int
left, right *node
}func (n *node) print(){
fmt.Printf("%d ", n.data)
}func (n *node) traverseFunc(f func(n *node)){ //在实现时,通过实现不同的 f,可以对遍历到的节点做不同的操作
if n == nil {
return
}
n.left.traverseFunc(f)
f(n)
n.right.traverseFunc(f)
}func main(){
//生成一棵树
root := node{0,nil,nil}
root.left = &node{2,nil,nil}
root.right = &node{6,nil,nil}
root.left.right = &node{4,nil,nil}
root.right.left = &node{1,nil,nil}
//对遍历到的节点做打印操作
root.traverseFunc(func(n *node){
n.print()
})
fmt.Println()
//对遍历到的节点先数据翻倍再做打印操作
root.traverseFunc(func(n *node){
n.data = n.data*2
n.print()
})
}结果:
2 4 0 1 6
4 8 0 2 12