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

Rust 全局变量的最佳实践 lazy_static/OnceLock/Mutex/RwLock

在实际项目开发中,难免需要用到全局变量,比如全局配置信息,全局内存池等,此类数据结构可能在多处需要被使用,保存为全局变量可以很方便的进行修改与读取。

在Rust中,如果只是读取静态变量是比较简单的,比如全局变量是一个usize或者& str等类型的值。如果全局变量是需要初始化产生的就比较复杂了,比如解析一个配置文件,然后把配置文件中的内容赋给全局变量。由于全局变量要被修改,这个全局变量得是可变的,也就是说产生了全局可变变量,而这种方式违反了Rust的设计原则。

一般方法

struct Config {id: u64,
}impl Config {fn new() -> Config {Config {id: 0,}}
}lazy_static::lazy_static! {static ref CACHE: Mutex<Config> = Mutex::new(Config::new());
}fn func1() {CACHE.lock().unwrap().id = 1;
}fn func2() {CACHE.lock().unwrap().id = 2;
}fn func3() -> u64 {return CACHE.lock().unwrap().id;
}fn main() {func1();let id1 = func3();println!("id1 = {}", id1);func2();let id2 = func3();println!("id2 = {}", id2);
}

这种方法一般可以满足需求,但是需要一开始就将变量初始化。
如果有未初始化的字段,可以使用Option等类型搞定。

更好的办法

use std::{sync::{OnceLock, RwLock},thread,time::Duration,
};struct AppData {count: i64,name: String,ptr: usize,
}static APP_SHARE: OnceLock<RwLock<AppData>> = OnceLock::new();fn th_loop1() {let app = APP_SHARE.get().unwrap();loop {{let app2 = app.read().unwrap();println!("th 1 read: {}", app2.count);if (app2.count > 60) {break;}}thread::sleep(Duration::new(1, 0));}println!("th 1 end!!");
}fn th_loop2() {let app = APP_SHARE.get().unwrap();loop {{let mut app2 = app.write().unwrap();app2.count += 1;println!("th 2 write: {}", app2.count);if (app2.count > 80) {break;}}thread::sleep(Duration::new(1, 0));}println!("th 2 end!!");
}fn main() {// 在这里初始化let app = APP_SHARE.get_or_init(|| {RwLock::new(AppData {count: 12 * 4 + 5,name: "abc".to_string(),ptr: (0xFF002403) as usize,})});{let app2 = app.read().unwrap();println!("init ok: {} {} {}", app2.count, app2.name, app2.ptr);}// 线程里面使用let t1 = thread::spawn(th_loop1);let t2 = thread::spawn(th_loop2);t1.join().unwrap();t2.join().unwrap();println!("===============");
}

这里的 AppData 一开始没有初始化,在程序运行时才进行。
能更好适应一般的全局变量需求!!

读多写少的情况,也可以这样:

use std::{cell::{Cell, RefCell},default,sync::{Arc, OnceLock, RwLock},thread,time::Duration,
};
struct T1 {a: i64,b: i64,
}
struct AppData {count: i64,name: String,ptr: usize,count2: RwLock<T1>,
}static APP_SHARE: OnceLock<AppData> = OnceLock::new();fn th_loop1() {let app = APP_SHARE.get().unwrap();loop {{let c2 = app.count2.read().unwrap();println!("th 1 read: {} {}", app.count, c2.a);if (app.count > 60 || c2.a > 10) {break;}}thread::sleep(Duration::new(1, 0));}println!("th 1 end!!");
}fn th_loop2() {let app = APP_SHARE.get().unwrap();loop {{let mut c2 = app.count2.write().unwrap();c2.a += 1;println!("th 2 write: {} {}", app.count, c2.a);if (app.count > 80 || c2.a > 20) {break;}}thread::sleep(Duration::new(1, 0));}println!("th 2 end!!");
}fn main() {// 在这里初始化let app = APP_SHARE.get_or_init(|| AppData {count: 12 * 4 + 5,name: "abc".to_string(),ptr: (0xFF002403) as usize,count2: RwLock::new(T1 { a: 1, b: 2 }),});{println!("init ok: {} {} {}", app.count, app.name, app.ptr);}// 线程里面使用let t1 = thread::spawn(th_loop1);let t2 = thread::spawn(th_loop2);t1.join().unwrap();t2.join().unwrap();println!("===============");
}

相关文章:

  • # linux从入门到精通(三)
  • UDP通信
  • [数据结构] 二叉树题目 (二)
  • 阿博图书馆管理系统:SpringBoot技术应用
  • c语言中的杨氏矩阵的介绍以及元素查找的方法
  • django drf 分页器
  • MP4 格式:前世今生与技术解析
  • HarmonyOS鸿蒙系统开发应用程序,免费开源DevEco Studio开发工具
  • 高级前端进阶:揭秘 MemFire Cloud 的强大助力
  • python和pyqt-tools安装位置
  • pyside6与协程
  • Python基础知识 (九)os模块、异常、异常的传递性
  • MySql语言操作数据库---MySql引擎,数据表,约束,基本查询,条件查询
  • 光耦知识分享 | 浅析施密特触发器光耦的主要特点
  • golang 反射的介绍和使用
  • CentOS7简单部署NFS
  • ES6核心特性
  • JS基础篇--通过JS生成由字母与数字组合的随机字符串
  • Lucene解析 - 基本概念
  • Map集合、散列表、红黑树介绍
  • mysql 5.6 原生Online DDL解析
  • ReactNativeweexDeviceOne对比
  • REST架构的思考
  • Webpack4 学习笔记 - 01:webpack的安装和简单配置
  • 机器学习学习笔记一
  • 爬虫模拟登陆 SegmentFault
  • 前端学习笔记之观察者模式
  • 微信端页面使用-webkit-box和绝对定位时,元素上移的问题
  • 微信小程序上拉加载:onReachBottom详解+设置触发距离
  • 支付宝花15年解决的这个问题,顶得上做出十个支付宝 ...
  • ###C语言程序设计-----C语言学习(6)#
  • #VERDI# 关于如何查看FSM状态机的方法
  • #调用传感器数据_Flink使用函数之监控传感器温度上升提醒
  • $ git push -u origin master 推送到远程库出错
  • (C语言)球球大作战
  • (JS基础)String 类型
  • (附源码)计算机毕业设计ssm基于B_S的汽车售后服务管理系统
  • (离散数学)逻辑连接词
  • (没学懂,待填坑)【动态规划】数位动态规划
  • (三十)Flask之wtforms库【剖析源码上篇】
  • (算法)N皇后问题
  • (算法)前K大的和
  • (一)ClickHouse 中的 `MaterializedMySQL` 数据库引擎的使用方法、设置、特性和限制。
  • (转) Face-Resources
  • (转)视频码率,帧率和分辨率的联系与区别
  • (轉貼) VS2005 快捷键 (初級) (.NET) (Visual Studio)
  • .NET 6 在已知拓扑路径的情况下使用 Dijkstra,A*算法搜索最短路径
  • .Net 6.0 Windows平台如何判断当前电脑是否联网
  • .NET 将多个程序集合并成单一程序集的 4+3 种方法
  • .NET 跨平台图形库 SkiaSharp 基础应用
  • .NET 设计模式—简单工厂(Simple Factory Pattern)
  • .NET 中创建支持集合初始化器的类型
  • .NET/C# 阻止屏幕关闭,阻止系统进入睡眠状态
  • .NET开源纪元:穿越封闭的迷雾,拥抱开放的星辰
  • .NET上SQLite的连接