Go 编程 | 连载 24 - 闭包 Closure

简介: Go 编程 | 连载 24 - 闭包 Closure

一、闭包 Closure

闭包 Closure 在某些语言如 Java、Python 或者 Ruby 中也被成为 Lambda 表达式或者匿名函数。

闭包是引用了自由变量的 匿名函数,被引用的自由变量和函数一同存在,即使已经离开了自由变量的环境也不会释放或者删除,在闭包中可以继续使用这个变量,也就是说闭包就等于 函数+引用环境

10e3123d54aa4bc69835cad27a5dc0be_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

Go 编程 | 连载 23 - 函数实现接口 中,我们知道函数可以通过定义一个函数类型来像结构体一样实例化;函数本身不存储任何信息,只有与引用环境结合后形成的闭包才具有“记忆性”。

函数是编译期静态的概念,而闭包是运行期动态的概念。

闭包可以对作用域上变量的引用进行修改,修改引用的变量就会对变量进行实际修改。

package main
import "fmt"
func main(){
   info := "Go"
   // 将一个匿名函数赋值给 f 变量
   f1 := func(){
      // 修改 info 变量的值
      info = "Elixir"
   }
   // 调用匿名函数
   f1()
   fmt.Println(info)
   stark := make(map[string]interface{})
   stark["name"] = "Tony Stark"
   stark["age"] = 33
   f2 := func() {
      stark["address"] = "NYC"
   }
   f2()
   fmt.Println(stark)
}
复制代码

执行上述代码,输出结果如下:

Elixir
map[address:NYC age:33 name:Tony Stark]
复制代码

二、闭包实现生成器

被捕获到比包中的变量让函数本身有了 “记忆”,闭包中的逻辑可以修改捕获的变量的值,变量就会跟随闭包的声明周期一直存在,闭包本身就如同变量一样有了 “记忆”。

package main
import "fmt"
func main() {
   // 创建一个累加器,初始值为 1
   outputSum := OutputSum(1)
   fmt.Println(outputSum())
   fmt.Printf("%p\n", outputSum)
   // 创建一个累加器,初始值为 10
   outputSum2 := OutputSum(10)
   fmt.Println(outputSum2())
   fmt.Printf("%p\n", outputSum2)
}
// 返回值是一个 func() int 类型既一个返回 int 类型的函数
func OutputSum(v int) func() int {
   return func() int {
      v ++
      return v
   }
}
复制代码

执行上述代码,输出结果如下:

2
0x108b1a0
11
0x108b180
复制代码

创建的两个函数实例虽然包含的变量不同,但其实是指向同一块内存,闭包会在运行时动态修改变量值。

闭包这种记忆的特性可以用于实现类似工厂模式的生成器。

package main
import "fmt"
func main() {
   genScore := GenScore("Stark")
   // 返回分数信息
   name, score := genScore()
   fmt.Println(name, score)
}
func GenScore(name string) func()(string, int) {
   // score
   score := 90
   return func() (string, int){
      return name, score
   }
}
复制代码

执行上述代码,输出结果如下:

Stark 90
复制代码

上述代码中 GenScore 返回值将 name 和 score 两个变量引入匿名函数,从而形成闭包。

闭包还具有一定的封装性,函数外部无法直接访问修改这些匿名函数中引用的变量,这与面向对象中的封装特性相似。


相关文章
|
2天前
|
安全 Go 数据处理
Go语言CSP编程实战:通道通信技术
Go语言CSP编程实战:通道通信技术
51 0
|
2天前
|
Go
高效Go语言编程:os包实用技术大揭示
高效Go语言编程:os包实用技术大揭示
48 0
|
6月前
|
算法 测试技术 Go
【Go 编程实践】从零到一:创建、测试并发布自己的 Go 库
解释了为何需要开发自己的 Go 库,以及如何创建、测试和发布。文章以 Asiatz 库为例,详细阐述了创建目录、初始化项目、编写代码、测试、编写文档和发布等步骤,并强调了开发自己的 Go 库的优点,包括代码复用性、可维护性和可测试性。
243 0
【Go 编程实践】从零到一:创建、测试并发布自己的 Go 库
|
2天前
|
SQL 前端开发 Go
编程笔记 GOLANG基础 001 为什么要学习Go语言
编程笔记 GOLANG基础 001 为什么要学习Go语言
|
2天前
|
Go C++
go 语言回调函数和闭包
go 语言回调函数和闭包
|
2天前
|
数据库连接 Go 数据库
【Go 语言专栏】Go 语言中的错误注入与防御编程
【4月更文挑战第30天】本文探讨了Go语言中的错误注入和防御编程。错误注入是故意引入错误以测试系统异常情况下的稳定性和容错性,包括模拟网络故障、数据库错误和手动触发错误。防御编程则强调编写代码时考虑并预防错误,确保程序面对异常时稳定运行。Go语言的错误处理机制包括多返回值和自定义错误类型。结合错误注入和防御编程,可以提升软件质量和可靠性,打造更健壮的系统。开发人员应重视这两方面,以实现更优质的软件产品。
|
2天前
|
网络协议 安全 Go
【Go语言专栏】Go语言中的WebSocket编程
【4月更文挑战第30天】本文介绍了在Go语言中使用WebSocket进行实时Web应用开发的方法。通过第三方包`gorilla/websocket`,开发者可建立WebSocket服务器和客户端。文中展示了如何创建服务器,升级HTTP连接,以及处理读写消息的示例代码。同时,客户端的创建和通信过程也得以阐述。文章还提及WebSocket的生命周期管理、性能与安全性考虑,以及实践中的最佳做法。通过学习,读者将能运用Go语言构建高效、实时的Web应用。
|
2天前
|
算法 Java Go
【Go语言专栏】Go语言中的泛型编程探索
【4月更文挑战第30天】Go语言新引入的泛型编程支持使得代码更通用灵活。通过类型参数在函数和接口定义中实现泛型,如示例中的泛型函数`Swap`和泛型接口`Comparator`。泛型应用包括数据结构、算法实现、函数包装和错误处理,提升代码复用与维护性。这一特性扩展了Go语言在云计算、微服务、区块链等领域的应用潜力。
|
2天前
|
SQL 关系型数据库 MySQL
Golang数据库编程详解 | 深入浅出Go语言原生数据库编程
Golang数据库编程详解 | 深入浅出Go语言原生数据库编程
|
2天前
|
网络协议 Linux Go
Go语言TCP Socket编程(下)
Go语言TCP Socket编程