5.4 Go 闭包

5.4 Go 闭包

闭包(closure):是由一个函数和其相关的引用环境组合的一个整体。(闭包=函数+引用环境)

package main

import (
    "fmt"
)

//是由一个函数和其相关的引用环境组合的一个整体。(闭包=函数+引用环境)
//函数addUpper返回值是个函数
//返回值是匿名函数 func(int)int
func test() func(int) int {
    //定义一个局部变量
    n := 10
    //返回一个匿名函数
    return func(x int) int {
        n += x
        return n
    }

}

/*
addUpper函数返回了一个匿名函数,这个匿名函数又引用了函数外的变量n,因此匿名函数+n组成了一个整体,形成闭包
当调用f函数时,n仅仅被初始化一次,因此每次调用形成累计

*/

func main() {
    //调用addUpper函数,获取返回值
    f := test()
    //此时f是匿名函数,对其传参调用
    fmt.Println(f(50)) //10+50=60
    fmt.Println(f(20)) //60+20=80
    fmt.Println(f(20)) //80+20=100 同一个f对象,保留了n的值

    f1 := test()
    fmt.Println(f1(10))
}

闭包代码修改

package main

import (
    "fmt"
)

//是由一个函数和其相关的引用环境组合的一个整体。(闭包=函数+引用环境)
//函数addUpper返回值是个函数
//返回值是匿名函数 func(int)int
func test() func(int) int {
    //定义一个局部变量
    n := 10
    var str = "oldboy"
    //返回一个匿名函数
    return func(x int) int {
        n += x
        str += string(36) //36对应的
        fmt.Println("此时str值:", str)
        return n
    }

}

/*
addUpper函数返回了一个匿名函数,这个匿名函数又引用了函数外的变量n,因此匿名函数+n组成了一个整体,形成闭包
当调用f函数时,n仅仅被初始化一次,因此每次调用形成累计

*/

func main() {
    //调用addUpper函数,获取返回值
    f := test()
    //此时f是匿名函数,对其传参调用
    fmt.Println(f(50)) //10+50=60
    fmt.Println(f(20)) //60+20=80
    fmt.Println(f(20)) //80+20=100 同一个f对象,保留了n的值

    //新的初始化
    f1 := test()
    fmt.Println(f1(10))
}

2. 闭包实战

package main

import (
    "fmt"
    "strings"
)

/*
1.makeSuffixFunc函数接收一个文件名后缀,如.png,且返回闭包
2.调用闭包,传入文件名前缀,如果没有后缀就添加后缀,返回 文件名.png
3.strings.HasSuffix可以判断指定字符串后缀
*/

func makeSuffixFunc(suffix string) func(string) string {
    //返回值闭包函数
    return func(filename string) string {
        //如果没有xx后缀,执行代码
        if !strings.HasSuffix(filename, suffix) {
            //则字符串拼接
            return filename + suffix
        }
        //否则有后缀名,则直接返回新文件名
        return filename
    }
}

func main() {
    //f1返回的是闭包函数,对此闭包函数进行功能性使用
    f1 := makeSuffixFunc(".png")

    fmt.Println(f1("苍老师"))  //没有后缀
    fmt.Println("小泽老师.png") //有后缀
}

总结:

1.makeSuffixFunc函数中的变量suffix和返回值匿名函数,组合成了一个闭包
2.由于闭包函数保留了上次引用的值suffix,只需要传入一次,即可反复使用

2.1. 函数式编程

支持将函数作为另一个函数的参数,叫回调函数。

支持将函数作为另一个函数的返回值。

package main

import "fmt"

//闭包函数
//函数体内有局部变量

func adder() func(int) int {
    sum := 0
    //return 的是一个闭包
    return func(v int) int {
        //引用自由变量,sum
        sum += v
        return sum
    }
}

//递归定义
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 := adder() is trivial and also works.
    a := adder2(0)
    for i := 0; i < 10; i++ {
        var s int
        s, a = a(i)
        fmt.Printf("0 + 1 + ... + %d = %d\n",
            i, s)
    }
}

go闭包-斐波那契数列

package main

import "fmt"

// 1,1,2,3,5,8,13,21,34,55...
//
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())
    fmt.Println(f())
    fmt.Println(f())
    fmt.Println(f())
    fmt.Println(f())
    fmt.Println(f())
    fmt.Println(f())
    fmt.Println(f())
    fmt.Println(f())
    fmt.Println(f())

}

2.2. python中闭包

def adder():
    sum = 0
    def f(value):
        nonlocal sum
        sum +=value 
        return sum 
    return f
posted @ 2019-07-27 21:34  笑得好美  阅读(108)  评论(0编辑  收藏  举报