Go基础之函数式编程

一.函数式编程 VS 函数指针

  • 函数是go语言中的一等公民,参数  变量  返回值都可以是函数
  • go语言并不是正统的函数式编程,go语言的函数式编程主要体现在 "闭包" 上
  • 高阶函数
  • 关于"闭包"的理解:阮一峰_学习Javascript闭包(Closure) 廖雪峰_javascript闭包 Golang-函数式编程(闭包)

注:正统的函数式编程:

  1. 不可变性:不能有状态,只有常量和函数
  2. 函数只能有一个参数

二.闭包 

  函数可以嵌套定义,即在一个函数内部可以定义另一个函数,有了嵌套函数这种结构,便会产生闭包问题.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 

你可能感兴趣的:(GoLang)