函数式编程:函数是一等公民,即参数、变量、返回值都可以是函数。
    高阶函数:函数的参数是函数。
    Go语言对函数式编程的支持主要体现在闭包上。
    闭包:
    image.png
    函数体中包括局部变量(在函数体内部定义的变量以及函数的参数)和自由变量(函数所处的环境)。
    函数体会对自由变量进行引用。

    1. import "fmt"
    2. func adder() func(int) int {
    3. sum := 0 // 自由变量
    4. // 返回的不仅是一个函数,而是一个闭包
    5. return func(v int) int { // v:局部变量
    6. sum += v
    7. return sum
    8. }
    9. }
    10. func main() {
    11. a := adder()
    12. for i := 0; i < 10; i++ {
    13. fmt.Printf("0 + 1 + ... + %d = %d\n", i, a(i))
    14. }
    15. }

    闭包的应用:
    ①斐波那契数列

    func fibonacci() func() int {
        a, b := 0, 1
        return func() int {
            a, b = b, a + b
            return a
        }
    }
    
    func main() {
        f := fibonacci()
    
        f() //1
        f() //1
        f() //2
        f() //3
        f() //5
        f() //8
        f() //13
        //...
    }
    

    ②为函数实现接口

    func fibonacci() intGen {
        a, b := 0, 1
        return func() int {
            a, b = b, a + b
            return a
        }
    }
    
    type intGen func() int
    
    func (g intGen) Read(p []byte) (n int, err error) {
        next := g()
        if next > 10000 {
            return 0, io.EOF
        }
        s := fmt.Sprintf("%d\n", next)
        return strings.NewReader(s).Read(p)
    }
    
    func printFileContents(reader io.Reader) {
        scanner := bufio.NewScanner(reader)
    
        for scanner.Scan() {
            fmt.Println(scanner.Text())
        }
    }
    
    func main() {
        f := fibonacci()
        printFileContents(f)
    }
    

    ③使用函数来遍历二叉树

    package tree
    
    func (node *Node) Traverse() {
        node.TraverseFunc(func(n *Node) {
            n.Print()
        })
        fmt.Println()
    }
    
    func (node *Node) TraverseFunc(f func(*Node)) {
        if node == nil {
            return 
        }
    
        node.Left.TraverseFunc(f)
        f(node)
        node.Right.TraverseFunc(f)
    }
    
    package main
    
    // ...
    
    func main() {
        // ...
        root.Traverse() // 0 2 3 4 5 
    
        nodeCount := 0
        root.TraverseFunc(func(node *tree.Node) {
            nodeCount++
        })
        fmt.Println("Node count:", nodeCount) // Node count: 5
    }
    

    Go语言闭包的特点:
    ①更为自然,不需要修饰如何访问自由变量
    ②没有lambda表达式,但是有匿名函数