使用 Rust 实现的基础的List 和 Watch 机制
使用 Rust 实现的基础的 List 和 Watch 机制在软件开发中我们经常需要一种机制来跟踪数据的变化并在变化发生时通知相关的观察者。这种模式被称为“观察者模式”或“发布-订阅模式”。在 Rust 中我们可以利用其所有权系统和并发安全特性实现一个轻量级的 List 和 Watch 机制。本文将带你一步步构建这个基础机制并通过代码示例展示其用法。## 什么是 List 和 Watch 机制想象一下你有一个购物清单List当清单上的商品价格发生变化时你想立刻收到通知Watch。在编程中List 是一个可共享的数据集合Watch 是一种监听器当 List 中的数据发生变化时所有注册的 Watch 都会收到回调通知。这种机制在很多场景下非常有用比如- 实时监控系统状态- 前端状态管理- 游戏中的事件处理- 分布式系统中的配置更新## 基础设计思路我们将用 Rust 实现一个简单的 List 和 Watch 机制。核心思想是1.List保存一个可变的数据列表并提供修改方法。2.Watcher一个闭包或函数当 List 变化时被调用。3.Registry管理所有 Watcher 的注册和通知。由于 Rust 的所有权规则我们需要使用Arc原子引用计数和Mutex互斥锁来安全地共享和修改数据。## 代码实现核心结构我们先定义基本类型和核心结构。为了让代码更直观我们使用std::sync::Arc和std::sync::Mutex。rustuse std::sync::{Arc, Mutex};use std::collections::HashMap;use std::thread;use std::time::Duration;// 定义一个泛型 List可以存储任何 Clone 类型的元素pub struct ListT: Clone { data: ArcMutexVecT, // 共享的可变数据 watchers: ArcMutexHashMapu64, Boxdyn Fn([T]) Send, // 观察者注册表 next_id: ArcMutexu64, // 用于生成唯一 ID}implT: Clone ListT { // 创建一个新的 List pub fn new() - Self { List { data: Arc::new(Mutex::new(Vec::new())), watchers: Arc::new(Mutex::new(HashMap::new())), next_id: Arc::new(Mutex::new(0)), } } // 添加元素到列表并通知所有观察者 pub fn push(self, item: T) { let mut data self.data.lock().unwrap(); data.push(item); self.notify_watchers(data); } // 删除最后一个元素并通知观察者 pub fn pop(self) - OptionT { let mut data self.data.lock().unwrap(); let result data.pop(); if result.is_some() { self.notify_watchers(data); } result } // 注册一个观察者返回一个 ID用于取消注册 pub fn watch(self, callback: Boxdyn Fn([T]) Send) - u64 { let mut id self.next_id.lock().unwrap(); *id 1; let current_id *id; let mut watchers self.watchers.lock().unwrap(); watchers.insert(current_id, callback); current_id } // 取消注册一个观察者 pub fn unwatch(self, id: u64) { let mut watchers self.watchers.lock().unwrap(); watchers.remove(id); } // 通知所有观察者 fn notify_watchers(self, data: VecT) { let watchers self.watchers.lock().unwrap(); for (_, callback) in watchers.iter() { callback(data.as_slice()); } } // 获取当前数据的快照 pub fn snapshot(self) - VecT { let data self.data.lock().unwrap(); data.clone() }}代码解释-data使用ArcMutexVecT存储数据允许多线程安全访问。-watchers是一个HashMap使用u64作为唯一 ID存储可调用的闭包。-push和pop方法在修改数据后调用notify_watchers。-watch方法注册一个闭包并返回一个 ID用于后续取消注册。-unwatch方法通过 ID 移除观察者。## 使用示例监控字符串列表现在让我们用这个 List 来监控一个字符串列表的变化。我们将创建两个观察者分别打印不同的信息。rustfn main() { // 创建一个存储字符串的 List let list List::new(); // 注册第一个观察者打印新列表内容 let id1 list.watch(Box::new(|data| { println!(观察者1: 列表更新了当前内容: {:?}, data); })); // 注册第二个观察者只打印元素个数 let id2 list.watch(Box::new(|data| { println!(观察者2: 当前有 {} 个元素, data.len()); })); // 添加一些元素 println!(添加元素...); list.push(苹果.to_string()); list.push(香蕉.to_string()); list.push(橘子.to_string()); // 移除一个元素 println!(\n移除元素...); list.pop(); // 取消第一个观察者 println!(\n取消观察者1...); list.unwatch(id1); // 再次添加元素只有观察者2会收到通知 println!(再次添加元素...); list.push(葡萄.to_string()); // 获取最终快照 let final_data list.snapshot(); println!(\n最终列表: {:?}, final_data);}运行结果预期输出添加元素...观察者1: 列表更新了当前内容: [苹果]观察者2: 当前有 1 个元素观察者1: 列表更新了当前内容: [苹果, 香蕉]观察者2: 当前有 2 个元素观察者1: 列表更新了当前内容: [苹果, 香蕉, 橘子]观察者2: 当前有 3 个元素移除元素...观察者1: 列表更新了当前内容: [苹果, 香蕉]观察者2: 当前有 2 个元素取消观察者1...再次添加元素...观察者2: 当前有 3 个元素最终列表: [苹果, 香蕉, 葡萄]这个示例清晰地展示了- 每次修改数据时所有观察者都会被调用。- 取消注册后观察者不再接收通知。- 可以通过snapshot获取当前数据的副本。## 高级用法多线程安全与性能考虑在实际应用中我们可能需要在多线程环境中使用这个 List。Rust 的Arc和Mutex已经保证了线程安全但需要注意性能问题。例如频繁的锁竞争可能成为瓶颈。下面是一个多线程示例展示如何在不同线程中操作 Listrustuse std::thread;fn main() { let list Arc::new(List::new()); // 在子线程中添加元素 let list_clone Arc::clone(list); let thread1 thread::spawn(move || { for i in 0..3 { list_clone.push(format!(线程1-{}, i)); thread::sleep(Duration::from_millis(100)); } }); // 在主线程中注册观察者 let id list.watch(Box::new(|data| { println!(主线程观察者: 列表长度 {}, data.len()); })); // 在子线程中移除元素 let list_clone2 Arc::clone(list); let thread2 thread::spawn(move || { thread::sleep(Duration::from_millis(250)); list_clone2.pop(); list_clone2.pop(); }); thread1.join().unwrap(); thread2.join().unwrap(); // 取消观察者 list.unwatch(id); println!(最终数据: {:?}, list.snapshot());}输出示例主线程观察者: 列表长度 1主线程观察者: 列表长度 2主线程观察者: 列表长度 3主线程观察者: 列表长度 2主线程观察者: 列表长度 1最终数据: [线程1-0]这个示例显示了- 多线程环境下观察者仍然能正确收到通知。- 锁机制保证了数据一致性但要注意死锁本例中不会发生因为锁持有时间很短。## 优化建议虽然我们的实现功能完整但还有改进空间1.使用RwLock替代Mutex如果读操作远多于写操作RwLock可以提供更好的并发性能。2.批量通知如果连续多次修改可以合并通知避免不必要的回调。3.异步支持对于 I/O 密集型应用可以改为异步回调避免阻塞主线程。4.类型安全当前watchers使用Boxdyn Fn存在动态分发开销。如果知道具体类型可以用泛型优化。## 总结本文通过 Rust 实现了一个基础但完整的 List 和 Watch 机制。我们学习了- 如何使用Arc和Mutex实现线程安全的数据共享。- 观察者模式的核心结构List 存储数据Watcher 接收通知。- 如何注册、取消注册观察者以及如何在数据变化时广播通知。- 多线程环境下的使用方法和注意事项。这个机制虽然简单但已经可以满足很多实际需求比如实时数据监控、事件驱动编程等。你可以在此基础上扩展比如增加条件过滤、支持异步回调、或者集成到 Web 框架中。Rust 的所有权系统和并发原语让这种实现既安全又高效非常适合构建可靠的后台服务。希望这篇文章能帮助你理解 Rust 中的观察者模式设计并给你在实际项目中带来启发。如果你有任何问题或改进建议欢迎在评论区交流

相关新闻

[项目开发经验分享]基于强类型事件的类型参数传递问题 —— 在 .NET Winform项目中如何设计泛型事件总线以实现UI与核心层的解耦

[项目开发经验分享]基于强类型事件的类型参数传递问题 —— 在 .NET Winform项目中如何设计泛型事件总线以实现UI与核心层的解耦

[项目开发经验分享]基于强类型事件的类型参数传递问题 —— 在 .NET Winform项目中如何设计泛型事件总线以实现UI与核心层的解耦 一、引言:从一道“头疼”的需求说起在 Winform 项目开发中,我们经常遇到这样的场景:用户点击一个“保存”按钮&…

2026/7/25 21:34:59阅读更多 →
AI智能体技能标准化:Agent Skills格式详解与实战创建指南

AI智能体技能标准化:Agent Skills格式详解与实战创建指南

在实际 AI 应用开发中,我们经常遇到一个核心矛盾:大语言模型(LLM)本身具备强大的通用推理能力,但对于特定领域、特定团队或特定业务流程的细节知识,它往往是缺失的。你无法指望一个通用模型天生就知道如何格式化你公司的周报、执行你团队特有的数据清洗流程,或者遵循一套…

2026/7/25 21:32:58阅读更多 →
大模型应用实战:核心痛点与工程化解决方案

大模型应用实战:核心痛点与工程化解决方案

1. 大模型应用现状与核心痛点过去两年里,大语言模型(LLM)以惊人的速度渗透到各行各业。从智能客服到代码生成,从文案创作到数据分析,这些"数字大脑"正在重塑我们的工作方式。但当我实际将GPT-4、Claude等模型…

2026/7/25 21:32:58阅读更多 →
深入linkify-it源码:理解Unicode支持的实现原理

深入linkify-it源码:理解Unicode支持的实现原理

深入linkify-it源码:理解Unicode支持的实现原理 【免费下载链接】linkify-it Links recognition library with full unicode support 项目地址: https://gitcode.com/gh_mirrors/li/linkify-it linkify-it 是一款强大的链接识别库,其核心优势在于…

2026/7/25 22:51:18阅读更多 →
DynamicJSON在iOS开发中的应用:网络请求与本地数据处理实践

DynamicJSON在iOS开发中的应用:网络请求与本地数据处理实践

DynamicJSON在iOS开发中的应用:网络请求与本地数据处理实践 【免费下载链接】DynamicJSON Access JSON properties dynamically like JavaScript using Swift 4.2s new dynamicMemberLookup feature 项目地址: https://gitcode.com/gh_mirrors/dy/DynamicJSON …

2026/7/25 22:51:18阅读更多 →
GoCourse完全指南:从零基础到精通Go语言的终极教程

GoCourse完全指南:从零基础到精通Go语言的终极教程

GoCourse完全指南:从零基础到精通Go语言的终极教程 【免费下载链接】GoCourse Go language course 项目地址: https://gitcode.com/gh_mirrors/go/GoCourse GoCourse是一个全面的Go语言学习项目,专为零基础学习者设计,通过丰富的实例和…

2026/7/25 22:51:18阅读更多 →
计算机组成原理4小时速成:冯·诺依曼结构、Cache与流水线核心考点解析

计算机组成原理4小时速成:冯·诺依曼结构、Cache与流水线核心考点解析

期末考试临近,计算机组成原理这门课是不是让你感到头疼?别担心,这篇文章就是为你准备的4小时速成指南。我们将用最直接的方式,帮你梳理核心知识点,让你在短时间内掌握考试重点,轻松应对期末考试。计算机组成…

2026/7/25 22:51:18阅读更多 →
flink分区

flink分区

Flink 分区是指‌数据流在算子子任务(SubTask)间的分发机制‌,核心作用是决定上游数据如何路由到下游并行实例,以支持并行计算、负载均衡及状态一致性 。‌‌核心概念‌物理本质‌:Flink 中的“分区”对应下游算子的‌…

2026/7/25 22:51:18阅读更多 →
SpringBoot+微信小程序充电桩管理系统毕业设计实战指南

SpringBoot+微信小程序充电桩管理系统毕业设计实战指南

如果你正在为计算机毕业设计发愁,不知道选什么项目既能体现技术实力又符合市场需求,那么充电桩管理系统可能正是你需要的选择。这个项目不仅紧贴新能源汽车行业的发展趋势,还涵盖了SpringBoot后端开发、微信小程序前端、数据库设计、支付集成…

2026/7/25 22:49:17阅读更多 →
Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/25 1:01:14阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/25 1:01:14阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/25 1:01:14阅读更多 →
突破文档下载限制:kill-doc让你看到的都能保存

突破文档下载限制:kill-doc让你看到的都能保存

突破文档下载限制:kill-doc让你看到的都能保存 【免费下载链接】kill-doc 看到经常有小伙伴们需要下载一些免费文档,但是相关网站浏览体验不好各种广告,各种登录验证,需要很多步骤才能下载文档,该脚本就是为了解决您的…

2026/7/25 0:01:16阅读更多 →
C++ string类模拟实现:从深拷贝到内存管理的完整指南

C++ string类模拟实现:从深拷贝到内存管理的完整指南

1. 项目概述:为什么我们要“手撕”string类?在C的学习道路上,尤其是从C语言过渡到C的“初阶”阶段,string类绝对是一个绕不开的核心。标准库里的std::string用起来太方便了,、find、substr,几个操作符和函数…

2026/7/25 0:01:16阅读更多 →
三角洲寻宝鼠工具:高效文件搜索与资源管理实战指南

三角洲寻宝鼠工具:高效文件搜索与资源管理实战指南

1. 先搞清楚“三角洲寻宝鼠”到底是什么工具从名称来看,“三角洲寻宝鼠”更像是一个资源查找或文件检索类工具,而不是游戏或娱乐软件。这类工具的核心价值在于帮助用户快速定位特定资源,比如文档、图片、压缩包或特定格式的文件。如果你经常需…

2026/7/25 0:01:16阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/24 23:01:03阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/25 19:03:04阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/25 19:03:04阅读更多 →