当前位置: 首页 > news >正文

GO 闭包

文章目录

        • 1. **累加器(状态保持器)**
        • 2. **缓存(记忆化)**
        • 3. **工厂函数**
        • 4. **函数式编程风格**
        • 5. **创建动态行为的函数**
        • 6. **控制访问权限**
      • 总结

高级闭包的使用在 Go 中非常灵活和强大,特别是在需要保存状态或对外部变量进行复杂操作的场景中。闭包可以捕获并保持外部变量的引用,从而允许函数在多次调用时共享状态。这使得它在需要持久化上下文或动态生成行为的地方非常有用。

1. 累加器(状态保持器)

闭包可以用来创建一个累加器,它可以在每次调用时保存并更新状态。这个例子展示了如何通过闭包创建一个简单的计数器。

package mainimport "fmt"// 创建一个计数器闭包
func counter() func() int {count := 0return func() int {count++return count}
}func main() {c1 := counter()fmt.Println(c1())  // 输出 1fmt.Println(c1())  // 输出 2fmt.Println(c1())  // 输出 3// 新的计数器实例,状态独立c2 := counter()fmt.Println(c2())  // 输出 1
}

这里 counter 函数返回了一个匿名函数,这个匿名函数引用并保存了 count 变量,即使 counter 函数已经返回,count 仍然存在并在后续调用中被修改。

2. 缓存(记忆化)

闭包可以用来创建缓存函数,通过保存已经计算过的结果来避免重复计算。这种模式在性能优化中非常有用,尤其是当某个操作成本较高时。

package mainimport "fmt"// 创建一个带缓存的 Fibonacci 函数
func fibonacci() func(int) int {cache := map[int]int{0: 0, 1: 1}return func(n int) int {if result, found := cache[n]; found {return result}cache[n] = fibonacci()(n-1) + fibonacci()(n-2)return cache[n]}
}func main() {fib := fibonacci()fmt.Println(fib(10))  // 输出 55fmt.Println(fib(50))  // 输出 12586269025
}

在这个例子中,fibonacci 函数返回一个闭包,该闭包使用一个缓存来存储 Fibonacci 序列的计算结果。每次计算一个新的 Fibonacci 数时,它会首先检查缓存,避免重复计算。

3. 工厂函数

闭包可以用于创建工厂函数,根据输入生成具有不同行为的函数。例如,你可以生成不同的数学操作函数。

package mainimport "fmt"// 创建一个工厂函数返回不同的数学操作闭包
func createOperation(op string) func(int, int) int {switch op {case "+":return func(a, b int) int {return a + b}case "-":return func(a, b int) int {return a - b}case "*":return func(a, b int) int {return a * b}case "/":return func(a, b int) int {if b != 0 {return a / b}return 0}default:return func(a, b int) int {return 0}}
}func main() {add := createOperation("+")fmt.Println(add(5, 3))  // 输出 8multiply := createOperation("*")fmt.Println(multiply(4, 2))  // 输出 8
}

在这个例子中,createOperation 是一个工厂函数,根据操作符参数返回对应的闭包函数,可以用于进行加、减、乘、除等不同的数学操作。

4. 函数式编程风格

通过闭包,你可以实现类似于函数式编程的操作,比如 mapfilterreduce,这些操作可以用来对数据进行处理。

package mainimport "fmt"// 使用闭包实现 map 操作
func mapFunc(arr []int, f func(int) int) []int {result := make([]int, len(arr))for i, v := range arr {result[i] = f(v)}return result
}func main() {numbers := []int{1, 2, 3, 4, 5}// 使用闭包对数组进行平方操作squares := mapFunc(numbers, func(n int) int {return n * n})fmt.Println(squares)  // 输出 [1 4 9 16 25]
}

这里通过闭包实现了一个简单的 mapFunc 操作,传入一个匿名函数用于对每个元素进行操作。

5. 创建动态行为的函数

闭包也可以根据外部输入生成具有不同行为的函数,比如生成一个带有自定义前缀的日志记录器。

package mainimport "fmt"// 创建一个日志记录器
func createLogger(prefix string) func(string) {return func(message string) {fmt.Println(prefix + ": " + message)}
}func main() {infoLogger := createLogger("INFO")errorLogger := createLogger("ERROR")infoLogger("This is an info message.")  // 输出 INFO: This is an info message.errorLogger("This is an error message.")  // 输出 ERROR: This is an error message.
}

通过使用闭包,createLogger 函数创建了带有特定前缀的日志记录器,每个日志记录器都具有自己独特的行为。

6. 控制访问权限

闭包可以用于实现类似于面向对象编程中的私有变量和方法。通过返回的闭包函数,你可以限制外部访问某些变量,只允许通过函数来操作这些变量。

package mainimport "fmt"// 创建一个闭包,用于限制对内部变量的直接访问
func bankAccount() (func(int) int, func() int) {balance := 0deposit := func(amount int) int {balance += amountreturn balance}getBalance := func() int {return balance}return deposit, getBalance
}func main() {deposit, getBalance := bankAccount()deposit(100)fmt.Println(getBalance())  // 输出 100deposit(50)fmt.Println(getBalance())  // 输出 150
}

在这个例子中,balance 变量只能通过 depositgetBalance 函数访问,从而实现了类似于私有变量的效果。

总结

高级闭包的常见使用场景包括:

  • 状态保持(如计数器)
  • 缓存和性能优化(记忆化)
  • 动态生成行为(工厂模式)
  • 函数式编程风格的操作(如 mapfilter
  • 控制访问权限(模拟私有变量)

闭包使得 Go 的函数行为更加灵活,能够轻松实现复杂的逻辑和状态管理,从而增强代码的表达力和简洁性。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • gi清除无用缓存
  • WPF 依赖属性与附加属性(面试长问)
  • 使用Linq进行多表查询(C#)
  • verilog vscode 与AI 插件
  • C#使用TCP-S7协议读写西门子PLC(四)
  • FlinkCDC 3.2.0 新增优点 Pattern Replacement in routing rules
  • docker 学习笔记
  • 初识爬虫1
  • 数据结构————栈的讲解(超详细!!!)
  • 基于SpringBoot的租房网站系统
  • AutoDL云计算GPT-SoVITS-TTS语音声色克隆语音合成
  • Rasa: Rasa Core中的相关概念及用法
  • Oracle数据恢复—Oracle数据库误删除表数据如何恢复数据?
  • WPF UpdateSourceTrigger属性
  • 使用 Milvus、vLLM 和 Llama 3.1 搭建 RAG 应用
  • (ckeditor+ckfinder用法)Jquery,js获取ckeditor值
  • Android框架之Volley
  • emacs初体验
  • go append函数以及写入
  • JavaScript 无符号位移运算符 三个大于号 的使用方法
  • Laravel 中的一个后期静态绑定
  • mysql中InnoDB引擎中页的概念
  • nginx(二):进阶配置介绍--rewrite用法,压缩,https虚拟主机等
  • Python代码面试必读 - Data Structures and Algorithms in Python
  • React16时代,该用什么姿势写 React ?
  • VUE es6技巧写法(持续更新中~~~)
  • vue2.0开发聊天程序(四) 完整体验一次Vue开发(下)
  • Zepto.js源码学习之二
  • 大型网站性能监测、分析与优化常见问题QA
  • 精彩代码 vue.js
  • 如何合理的规划jvm性能调优
  • 使用前端开发工具包WijmoJS - 创建自定义DropDownTree控件(包含源代码)
  • 学习笔记:对象,原型和继承(1)
  • 用Visual Studio开发以太坊智能合约
  • k8s使用glusterfs实现动态持久化存储
  • ​七周四次课(5月9日)iptables filter表案例、iptables nat表应用
  • ​软考-高级-信息系统项目管理师教程 第四版【第14章-项目沟通管理-思维导图】​
  • ​总结MySQL 的一些知识点:MySQL 选择数据库​
  • #Datawhale X 李宏毅苹果书 AI夏令营#3.13.2局部极小值与鞍点批量和动量
  • #define 用法
  • #Linux杂记--将Python3的源码编译为.so文件方法与Linux环境下的交叉编译方法
  • #pragam once 和 #ifndef 预编译头
  • $.ajax()方法详解
  • (152)时序收敛--->(02)时序收敛二
  • (Java企业 / 公司项目)点赞业务系统设计-批量查询点赞状态(二)
  • (pojstep1.1.2)2654(直叙式模拟)
  • (ZT) 理解系统底层的概念是多么重要(by趋势科技邹飞)
  • (第8天)保姆级 PL/SQL Developer 安装与配置
  • (非本人原创)我们工作到底是为了什么?​——HP大中华区总裁孙振耀退休感言(r4笔记第60天)...
  • (附源码)python房屋租赁管理系统 毕业设计 745613
  • (转)MVC3 类型“System.Web.Mvc.ModelClientValidationRule”同时存在
  • (轉)JSON.stringify 语法实例讲解
  • .dwp和.webpart的区别
  • .net 7和core版 SignalR
  • .NET Core跨平台微服务学习资源