GO 闭包

ops/2024/9/19 21:53:06/ 标签: golang, 开发语言, 后端, go, 闭包

文章目录

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

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

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

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

go">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. 缓存(记忆化)

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

go">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. 工厂函数

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

go">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,这些操作可以用来对数据进行处理。

go">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. 创建动态行为的函数

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

go">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. 控制访问权限

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

go">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 的函数行为更加灵活,能够轻松实现复杂的逻辑和状态管理,从而增强代码的表达力和简洁性。


http://www.ppmy.cn/ops/113133.html

相关文章

Python 课程11-Web 开发

前言 Web 开发已经成为现代软件开发的核心领域之一,许多应用程序和服务都通过 Web 来与用户和其他系统交互。Python 作为一门广泛使用的编程语言,提供了多种 Web 开发框架,其中最流行的两个框架是 Flask 和 Django。 Flask 是一个轻量级的 W…

Linux命令:对文本文件的内容进行排序的工具sort详解

目录 一、概述 二、用法 1、 基本语法 2、 常用选项 3、获取帮助 三、示例 1. 基本用法 2. 按数字排序 3. 按第二列排序 4. 逆序排序 5. 删除重复行 6. 忽略大小写排序 7. 按人类可读的数值排序 8. 按版本号排序 四、高级用法 1. 与 uniq 结合使用去重 2. 与 gr…

简单题66-加一(Python)20240918

问题描述&#xff1a; python class Solution(object):def plusOne(self, digits):""":type digits: List[int]:rtype: List[int]"""n len(digits)# 从最后一位开始处理进位for i in range(n - 1, -1, -1):if digits[i] < 9:digits[i] 1re…

音视频入门基础:AAC专题(9)——FFmpeg源码中计算AAC裸流每个packet的duration和duration_time的实现

音视频入门基础&#xff1a;AAC专题系列文章&#xff1a; 音视频入门基础&#xff1a;AAC专题&#xff08;1&#xff09;——AAC官方文档下载 音视频入门基础&#xff1a;AAC专题&#xff08;2&#xff09;——使用FFmpeg命令生成AAC裸流文件 音视频入门基础&#xff1a;AAC…

黑神话悟空mac可以玩吗

黑神话悟空mac上能不能玩对于苹果玩家来说很重要&#xff0c;那么黑神话悟空mac可以玩吗&#xff1f;目前是玩不了了&#xff0c;没有针对ios系统的版本&#xff0c;只能之后在云平台上找找了&#xff0c;大家可以再观望下看看。 黑神话悟空mac可以玩吗 ‌使用CrossOver‌&…

c#:System.Text.Json 的使用四(如何忽略[JsonPropertyName])

环境&#xff1a; .net 6.0vs2022 系列篇&#xff1a; 《c#&#xff1a;System.Text.Json 的使用一》 《c#&#xff1a;System.Text.Json 的使用二》 《c#&#xff1a;System.Text.Json 的使用三&#xff08;从Newtonsoft迁移&#xff09;》 《c#&#xff1a;System.Text.Json…

Android Framework(六)WMS-窗口显示流程——窗口内容绘制与显示

文章目录 窗口显示流程明确目标 窗户内容绘制与显示流程窗口Surface的5种状态完整流程图 应用端处理finishDrawingWindow 的触发 system_service处理WindowState状态 -- COMMIT_DRAW_PENDING本次layout 流程简述applySurfaceChangesTransaction 方法概览READY_TO_SHOW和HAS_DRA…

【ARM】SOC的多核启动流程详解

基础概念 • cold boot 冷启动&#xff0c;一上电就开始运行 • warm boot 热启动&#xff0c;只是复位一下 • Primary boot 只给主核跑的那段代码 • Secondary boot 给从核跑的代码 还两种配置&#xff1a; • reset地址是可编程的&#xff0c;则会配置PROGRAMMABLE_RESET_…

Git项目管理工具

分布式版本控制系统 实际操作: 设置用户信息 git config --global user.name “itcast” git config --global user.email "hello@itcast.cn" </

TCP Analysis Flags 之 TCP ZeroWindow

前言 默认情况下&#xff0c;Wireshark 的 TCP 解析器会跟踪每个 TCP 会话的状态&#xff0c;并在检测到问题或潜在问题时提供额外的信息。在第一次打开捕获文件时&#xff0c;会对每个 TCP 数据包进行一次分析&#xff0c;数据包按照它们在数据包列表中出现的顺序进行处理。可…

MacBook苹果电脑安装JDK8、JDK17教程,环境变量配置 + 快速切换JDK版本

MacBook苹果电脑安装JDK8、JDK17教程&#xff0c;环境变量配置 快速切换JDK版本 MacBook M1 安装JDK及环境变量配置 1、在Oracle官网下载JDK 2、安装JDk 3、配置环境变量 4、快速切换 1.下载JDK&#xff08;官网&#xff09; 1.1官网下载dmg安装包 Java Archive | Oracle J…

GPT代码记录

#include <iostream>// 基类模板 template<typename T> class Base { public:void func() {std::cout << "Base function" << std::endl;} };// 特化的子类 template<typename T> class Derived : public Base<T> { public:void…

大模型分离架构学习记录

1、大模型相关名词 TOE&#xff08;TCP Offload Engine&#xff09;是指TCP卸载引擎。它是一种网络技术&#xff0c;通过将TCP/IP协议栈的一部分处理任务从主机的CPU卸载到网卡&#xff1b; 也就是RDMANVLink :在单台服务器内 8 块 GPU 卡通过 NVLink 连接。不同服务器之间的 …

MySQL——数据库的高级操作(一)数据备份与还原(1)数据的备份

在操作数据库时&#xff0c;难免会发生一些意外造成数据丢失。例如&#xff0c;突然停电、管理员的操作失误都可能导致数据的丢失。为了确保数据的安全&#xff0c;需要定期对数据库进行备份&#xff0c;这样&#xff0c;当遇到数据库中数据丢失或者出错的情况&#xff0c;就可…

vue3+ant design vue 中弹窗自定义按钮设置及以冒号为基准布局

1、自定义弹窗按钮&#xff0c;去除取消和确定按钮。&#xff08;网上很多方法都是说通过插槽来实现&#xff0c;但是试了下不生效&#xff0c;那既然插槽不生效的话&#xff0c;干脆直接写按钮就好了&#xff09; <a-modalv-model:open"open"title"人员信息…

探索Go语言中的Goroutine并发机制

什么是Goroutine 在Go语言中,Goroutine 是程序中最基本的并发单位。事实上,每个Go程序都会自动创建一个goroutine,那就是主goroutine,程序启动时会立即执行。Goroutine是Go语言中处理并发问题的核心工具,因此理解它的工作原理至关重要。 简而言之,Goroutine是并发执行的…

ubuntu20.04编译mesa

依赖 # drm git clone https://gitlab.freedesktop.org/mesa/drm.git meson builddir/ ninja -C builddir/ install# wayland git clone https://gitlab.freedesktop.org/wayland/wayland.git meson setup builddir -Ddocumentationfalse ninja -C builddir/ install编译 sud…

qt绘制时钟

代码 #include "widget.h" #include "ui_widget.h"#include <QWidget> #include <QPaintEvent> //绘图事件 #include <QDebug> //测试 #include <QPainter> //画家 #include <QPen> //笔 #include <QBrush> //画刷 …

Vue路由:Vue router

目录 路由的基本概念 1. 路由 2. 单页应用SPA 3.前端路由的实现方式 3.1Hash模式 3.2History模式 Vue router 4 1.概述 2.安装使用 3.基础用法 3.1路由匹配规则声明 3.2动态路由匹配 3.3路由命名 3.4路由重定向 3.5路由嵌套 3.6命名视图 3.6声明式导航&编程…

python-奖金/贪心的小明

一&#xff1a;奖金 题目描述 企业发放的奖金根据利润提成。利润低于或等于 100000 元的&#xff0c;奖金可提 10%&#xff1b; 利润高于 100000 元&#xff0c;低于 200000 元&#xff08; 100000<I≤200000&#xff09;时&#xff0c;低于 100000 元的部分按 10% 提成&…