Go 语言中的闭包理解

1,215 阅读2分钟

这是我参与8月更文挑战的第15天,活动详情查看:8月更文挑战

什么是闭包

闭包是函数与相关环境组合成的实体(闭包= 函数+引用环境)

image.png

维基百科讲,闭包(Closure),是引用了自由变量的函数。闭包在实现上是一个结构体,它存储了一个函数(通常是其入口地址)和一个关联的环境(相当于一个符号查找表)。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。

匿名函数

匿名函数是指不需要定义函数名的一种函数实现方式。 匿名函数是由一个不带函数名的函数声明和函数体组成。

在一个函数内部可以定义另一个函数。

匿名函数的优越性在于可以直接使用函数内的变量,不必声明

func getSequence() func() int {
   i:=0
   return func() int {
      i+=1
     return i  
   }
}

上面的 func 就是匿名函数。

import (
"fmt"
"math"
   "testing"
)
func TestNiMing(t *testing.T) {
   getSqrt := func(a float64) float64 {
      return math.Sqrt(a)
   }
   fmt.Println(getSqrt(4))
}

输出结果:

2

闭包代码

package bibao

import (
   "fmt"
   "testing"
)

func NextNumber() func() int {
   i := 0
   b := func() int {
      i++
      fmt.Println(i)
      return i
   }
   return b
}
func TestBiBao(t *testing.T) {
   next := NextNumber()
   next()
   next()
   next()
   NextNumber() //不会输出i
}

输出结果:

=== RUN   TestBiBao
1
2
3
--- PASS: TestBiBao (0.00s)
PASS

发现没,闭包和匿名函数有点相似。

Go 语言是通过匿名函数实现闭包的。

闭包的本质

闭包是包含自由变量的代码块,变量不在代码块内或者任何全局上下文中定义,而是在定义代码块的环境中定义。

由于自由变量在代码块中,所以只要比闭包还被使用,那么自由变量以及引用的对象就不会被释放,要执行代码自由变量绑定的计算机环境中

也就是说闭包拥有记忆效应,闭包中的逻辑可以修改闭包捕获的变量,变量回跟随闭包的生命周期一直存在,闭包本身如同变量一样拥有了记忆效应。

func NextNumber() func() int {
   i := 0
   b := func() int {
      i++
      fmt.Println(i)
      return i
   }
   return b
}
func TestBiBao(t *testing.T) {
   next := NextNumber()
   next()
   next()
   next()

   next1 := NextNumber()
   next1()
   NextNumber() //不会输出i
}

执行结果:

=== RUN   TestBiBao
1
2
3
1
--- PASS: TestBiBao (0.00s)
PASS

可以通过新的对象方式,开启一个新的闭包