go 的函数式编程

在 go 语言中,函数是一等公民。函数既可以作为参数传入,也可以作为返回值返回。
go 语言的函数式编程最典型的例子就是 闭包。

闭包是什么呢?

简单讲,闭包就是指有权访问另一个函数作用域中的变量的函数。
它由两部分构成:函数,以及创建该函数的环境。环境由闭包创建时在作用域中的任何局部变量组成。
外部函数调用之后其变量对象本应该被销毁,但闭包的存在使我们仍然可以访问外部函数的变量对象,这就是闭包的重要概念。

闭包

package main

import "fmt"

func fib() func() int {
    a,b := 0,1
    return func() int {
        b,a = a+b,b
        return b
    }
}

func main() {
    f := fib()
    for i := 0 ; i < 20;i++ {
        fmt.Printf("%d ",f())
    }
}
// 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946
为函数生成接口

上面的例子中,f() 是每执行一遍的话 ,会生成一个新的斐波那契数。可以把他实现成为一个read的接口。那么就可以使用 scanner.Scan()。像读文件一样打印斐波那契数列。

package main

import (
    "bufio"
    "fmt"
    "io"
    "strings"
)

func fib() IntGen {
    a,b := 0,1
    return func() int {
        b,a = a+b,b
        return b
    }
}

type IntGen func() int

func (g IntGen) Read(p []byte) (n int,err error) {
    next := g()
    if next > 1000000 {
        return 0,io.EOF
    }
    s := fmt.Sprintf("%d ",next)
    return strings.NewReader(s).Read(p)
}

func PrintFib(read io.Reader) {
    scanner := bufio.NewScanner(read)

    for scanner.Scan() {
        fmt.Println(scanner.Text())
    }
}
func main() {
    f := fib()
    PrintFib(f)
} 
传入函数来解决问题

假设现在有一个遍历二叉数的函数。他只是做了打印的操作,那能否使用之前的所学到的知识,再丰富其功能呢。

func (t *TreeNode) Traverse() {
    if t == nil {
        return
    }

    t.Left.Traverse()
    fmt.Println(t.Val)
    t.Right.Traverse()
}

用闭包改造后,不仅可以打印出每一个值,而且可以打印出一共有多少个节点。

func (t *TreeNode) Traverse() {
    cnt := 0
    t.TraverseFunc(func(node *TreeNode) {
        fmt.Printf("%d ",node.Val)
        cnt ++
    })
    fmt.Println("\nNode cnt is",cnt)
}

func (t *TreeNode) TraverseFunc(f func (*TreeNode) ) {
    if t == nil {
        return
    }

    t.Left.TraverseFunc(f)
    f(t)
    t.Right.TraverseFunc(f)
}

你可能感兴趣的:(go 的函数式编程)