函数式编程

  • 函数式一等公民:参数,变量,返回值都可以是函数
  • 高阶函数:函数的参数也可以是一个函数
  • 函数 -> 闭包
func adder() func(int) int {

    sum := 0
    return func(v int) int {
        sum += v
        return sum
    }
}

func main() {

    a := adder()
    for i := 0; i < 10; i++  {
       // 0 + 1 + ... + 0 = 0
       // 0 + 1 + ... + 1 = 1
       // 0 + 1 + ... + 2 = 3
       // 0 + 1 + ... + 3 = 6
       // 0 + 1 + ... + 4 = 10
       // 0 + 1 + ... + 5 = 15
       // 0 + 1 + ... + 6 = 21
       // 0 + 1 + ... + 7 = 28
       // 0 + 1 + ... + 8 = 36
       // 0 + 1 + ... + 9 = 45
        fmt.Printf("0 + 1 + ... + %d = %d\n", i, a(i) )
    }
}

上面的代码主要介绍了go 语言中的闭包,在函数返回时,并不是直接返回一个结果,而是返回类似下图结构的一个闭包

-w500

正统函数式编程

adder2函数与adder 函数的区别是,adder2会少一个自由变量,但相对来说更不容易阅读一些

type iAdder func(int) (int, iAdder)

func adder2(base int) iAdder {
    return func(v int) (int, iAdder) {
        return base + v, adder2(base + v)
    }
}

func main() {

    a := adder2(0)
    for i := 0; i < 10; i++  {
        var s int
        s, a = a(i)
       // 0 + 1 + ... + 0 = 0
       // 0 + 1 + ... + 1 = 1
       // 0 + 1 + ... + 2 = 3
       // 0 + 1 + ... + 3 = 6
       // 0 + 1 + ... + 4 = 10
       // 0 + 1 + ... + 5 = 15
       // 0 + 1 + ... + 6 = 21
       // 0 + 1 + ... + 7 = 28
       // 0 + 1 + ... + 8 = 36
       // 0 + 1 + ... + 9 = 45
        fmt.Printf("0 + 1 + ... + %d = %d\n", i, s)
    }
}

python 中的闭包

python 原生支持闭包
可以使用__closure_来查看闭包的内容

def adder():
    sum = 0
    def f(value):
        nonlocal sum
        sum += value
        return sum
    return f

c++的闭包

过去stl或者boost带有类似的库,c++11及以后开始支持闭包

auto adder() {
    auto sum = 0;
    return [=] (int value) mutable {
        sum += value;
        return sum;
    };
}

java 中的闭包

1.8以后使用Function接口和Lambda表达式来创建函数对象,匿名类或Lambda表达式均支持闭包

Function<Integer, Integer> adder() {
    final Holder<Integer> sum = new Holder<>(0);
    return (Integer value) -> {
        sum.value += value;
        return sum.value;
    }
}

c# 中的闭包

C# 中可以使用Func来进行闭包

Func<int> adder() {
    var sum = 0;
    return (int value) => {
        sum += value;
        return sum;
    };
}

闭包的应用

斐波那契数列

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

func main() {

    f := fibonacci()
    fmt.Println(f()) // 1
    fmt.Println(f()) // 1
    fmt.Println(f()) // 2
    fmt.Println(f()) // 3
    fmt.Println(f()) // 5
    fmt.Println(f()) // 8
}

使用函数遍历二叉树

通过下面的例子我们可以看到,闭包的使用可以减少我们写很多代码

func (node *Node) TraverseFunc(f func(*Node)) {
    if node == nil {
        return
    }

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

func (node *Node) Traverse() {
    node.TraverseFunc(func(node *Node) {
        node.Print()
    })
    fmt.Println()
}


What doesn’t kill you makes you stronger.