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 两个变量引入匿名函数,从而形成闭包。

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


相关文章
|
1月前
|
数据库连接 Go 数据库
Go语言中的错误注入与防御编程。错误注入通过模拟网络故障、数据库错误等,测试系统稳定性
本文探讨了Go语言中的错误注入与防御编程。错误注入通过模拟网络故障、数据库错误等,测试系统稳定性;防御编程则强调在编码时考虑各种错误情况,确保程序健壮性。文章详细介绍了这两种技术在Go语言中的实现方法及其重要性,旨在提升软件质量和可靠性。
38 1
|
1月前
|
数据采集 监控 Java
go语言编程学习
【11月更文挑战第3天】
42 7
|
1月前
|
Unix Linux Go
go进阶编程:Golang中的文件与文件夹操作指南
本文详细介绍了Golang中文件与文件夹的基本操作,包括读取、写入、创建、删除和遍历等。通过示例代码展示了如何使用`os`和`io/ioutil`包进行文件操作,并强调了错误处理、权限控制和路径问题的重要性。适合初学者和有经验的开发者参考。
|
2月前
|
Java 大数据 Go
Go语言:高效并发的编程新星
【10月更文挑战第21】Go语言:高效并发的编程新星
54 7
|
2月前
|
Go 数据处理 调度
Go语言中的并发模型:解锁高效并行编程的秘诀
本文将探讨Go语言中独特的并发模型及其在现代软件开发中的应用。通过深入分析 Goroutines 和 Channels,我们将揭示这一模型如何简化并行编程,提升应用性能,并改变开发者处理并发任务的方式。不同于传统多线程编程,Go的并发方法以其简洁性和高效性脱颖而出,为开发者提供了一种全新的编程范式。
|
3月前
|
存储 缓存 Go
go语言编程系列(五)
go语言编程系列(五)
|
3月前
|
搜索推荐 Java 编译器
go语言编程系列(四)
go语言编程系列(四)
|
3月前
|
存储 JSON 安全
go语言编程系列(七)
go语言编程系列(七)
|
3月前
|
存储 安全 编译器
go语言编程系列(六)
go语言编程系列(六)
|
3月前
|
自然语言处理 Java 测试技术
go语言编程系列(二)
go语言编程系列(二)