美文网首页
Go语言中的闭包理解

Go语言中的闭包理解

作者: 码二哥 | 来源:发表于2020-02-05 10:32 被阅读0次

参考

http://c.biancheng.net/view/59.html
https://www.jianshu.com/p/faf7ef7fbcf8
https://www.calhoun.io/5-useful-ways-to-use-closures-in-go/

关键点

希望通过下面的关键词,实现目的:能够快速回忆理解复习 知识点:

1、闭包 = 匿名函数 + 引用环境

2、函数,是编译器静态的概念

3、闭包,是运行期动态的概念

4、闭包的本质什么?要解决什么问题
可以从以下几个方面去理解:

  • 将函数增加记忆功能,

  • 函数的视角去看,将函数运行结束后状态能够保存下来

  • 引用环境的视角去看,对同一块内存,用同一个函数 操作后的结果,可以操作一次,也可以操作多次

  • 闭包很适合迭代场景下的使用,可以迭代一次,也可以迭代多次

  • 引用环境,可以认为是中间态,或者说,运行态 , 或者说 一个变量,经过匿名函数处理后,会产生不同的,就是不同的状态

  • 还可以从另外一个角度去分析:一个函数内部修改了某个变量(内存),等这个函数执行完毕后,这个变量还在,下次再次执行这个函数的时候,可以继续获取到当前的变量,即执行这个函数的时候,都是在上次的执行结果之上进行的;那么,这个变量,肯定是在函数外部定义的,然后,对这个变量和函数进行封装成一个函数,那么整体就是闭包了。递归操作,就有这种特性
    含有以上特征时,可以考虑使用闭包

1、什么闭包?

简单的说,就是

闭包 = 匿名函数 + 引用环境

同一个函数与不同引用环境的组合,可以形成不同的实例,如下图所示:

闭包与函数引用

2、函数是否可以存储状态,或者说,存储信息?

一个函数类型就像结构体一样,可以被实例化,
函数本身不存储任何信息,只有与引用环境结合后的闭包,才具有"记忆性";

调用函数时会创建内存,
但是,当函数调用结束后,内存释放掉了,
因此, 函数本身不具备存储任何信息的能力

3、什么是 引用环境

由于闭包把函数和运行时的引用环境打包成为一个新的整体, 所以就解决了函数编程中的前嵌套所引发的问题。
当每次调用包含闭包的函数时都将返回一个新的闭包实例,这些实例之间是隔离的, 分别包含调用时不同的引用环境现场。
不同于函数,闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。

对引用环境的说明

4、闭包的本质是什么呢?

可以从以下几个方面去理解:
1、将函数增加记忆功能,

2、从函数的视角去看,将函数运行结束后的状态能够保存下来

3、从引用环境的视角去看,对同一块内存,用同一个函数 操作后的结果,可以操作一次,也可以操作多次

4、闭包很适合迭代场景下的使用,可以迭代一次,也可以迭代多次

5、引用环境,可以认为是中间态,或者说,运行态
含有以上特征时,可以考虑使用闭包

5、什么场景下使用闭包呢?

5.1、例子 1:计算一个切片的和

需求分析:
一个切片是有至少一个元素以上构成的,那么切片的和是一个累加的过程,
既然是累加的过程就会有 中间过程,中间态,
把中间过程(中间态)看做是一个引用环境,

package main

import "fmt"

func sum() func(int) int  {
    var num int

    return func(temp int) int {
        num += temp
        return num
    }
}

func main() {
    data := []int{
        2,3,4,1,5,1,
    }
    s := sum()
    var result int
    for _, value := range data{
        result = s(value)
    }

    fmt.Printf("result = %d\n", result)

}

image

5.2、例子 2:计算一下某个函数调用次数

package main

import "fmt"

func createApi(str string) {
    fmt.Printf("createApi recevice str =\t%s\n", str)
}

func countFunc(f func(string)) func(string) int {
    var count int

    return func(str string) int {
        f(str)
        count++
        return count
    }
}

func main() {
    cf := countFunc(createApi)

    cf("hello")
    cf("world")

    result := cf("Golang")

    fmt.Printf("call createApi num %d", result)
}

image

5.3、例子 3: 斐波那契数列

如:
1,2,3,5,8,13,21,34,……

package main

import "fmt"

func makeFibGen() func() int {
    f0 := 0
    f1 := 1

    return func() int {
        f1, f0 = (f0 + f1), f1

        return f0
    }
}

func main() {
    gen := makeFibGen()

    for i := 0; i < 10; i++ {
        fmt.Printf("%d ", gen())
    }
}

image

6、闭包中遇到

请参考下面的博客:
https://www.jianshu.com/p/fa21e6fada70
https://blog.csdn.net/chunyuan314/article/details/81247746
https://www.jianshu.com/p/faf7ef7fbcf8
https://blog.csdn.net/chunyuan314/article/details/81247746

问题核心是:

  • 闭包中的匿名函数,在引用环境时,不是拷贝,而是引用

  • for循环会很快执行结束,而协程还未开始,导致协程在获取for循环给的变量时,拿到的都是 最后一个变量

  • 解决措施,

    • 在创建协程后,需要添加阻塞,如休息一小段时间

    • 传递for循环的变量时,先复制给 一个临时变量,而临时变量属于值拷贝,从而协程拿到了属于自己的变量

    • 还可以使用通道,如 https://blog.csdn.net/li_101357/article/details/80196650

相关文章

  • Go语言中的闭包理解

    参考 http://c.biancheng.net/view/59.html[http://c.biancheng...

  • Go语言中的函数 为什么是一等公民

    关键点 Go语言中,支持: 普通函数 匿名函数 闭包 在Go语言中,函数属于一等公民(first-class)? ...

  • go 学习笔记之10 分钟简要理解 go 语言闭包技术

    闭包是主流编程语言中的一种通用技术,常常和函数式编程进行强强联合,本文主要是介绍 Go 语言中什么是闭包以及怎么理...

  • go语言中的闭包

    基本介绍:闭包就是一个函数和其相关的引用环境组合的一个整体。 对上面代码的说明和总结: 1、AddUpper是一个...

  • [Python]闭包的理解和使用

    闭包广泛使用在函数式编程语言中,虽然不是很容易理解,但是又不得不理解。 闭包是什么? 在一些语言中,在函数中可以(...

  • Kotlin闭包

    闭包的概念 闭包(Closure)的概念总是存在于各种支持函数式编程的语言中。首先理解什么是闭包,这里取JavaS...

  • Kotlin闭包

    闭包的概念 闭包(Closure)的概念总是存在于各种支持函数式编程的语言中。首先理解什么是闭包,这里取JavaS...

  • 【go语言学习】函数function

    函数是组织好的、可重复使用的、用于执行指定任务的代码块。Go语言中支持函数、匿名函数和闭包,并且函数在Go语言中属...

  • (译)Go 语言中的闭包

    原文链接:Special Memory Powers of Go Closures 通常 Go 语言中的命名函数只...

  • Go 语言极速入门6 - 闭包

    adder() 函数的返回值是一个函数注意:在 Go 语言中,闭包是可以含有自由变量的

网友评论

      本文标题:Go语言中的闭包理解

      本文链接:https://www.haomeiwen.com/subject/gnijxhtx.html