用Option<…>作为静态变量来存储单例对象的原始全局指针,用get_or_insert_with方法来初始化单例对象
最严谨的方法是用 Arc
use std::sync::Arc;use std::sync::Mutex;struct Point {pub x: u32,pub y: u32,}impl Point {pub fn get_instance() -> Arc<Mutex<Point>> {// 全局变量作为Option类型,get_or_insert_with在判断自己是否为None时,// 也可能有多线程竞争的问题,最安全的方法是给Option也套一个锁。// 可以使用第三方库once_cell实现更简单的写法static mut POINT: Option<Arc<Mutex<Point>>> = None;unsafe {// Rust中使用可变静态变量都是unsafe的POINT.get_or_insert_with(|| {// 初始化单例对象的代码Arc::new(Mutex::new(Point {x: 0, y: 0}))}).clone()}}}
once_cell提供了unsync::OnceCell和sync::OnceCell这两种Cell(字面意思,前者用于单线程,后者用于多线程),用来存储堆上的信息,并且具有最多只能赋值一次的特性
use std::{env, io};use once_cell::sync::OnceCell;#[derive(Debug)]pub struct Logger {// ...}static INSTANCE: OnceCell<Logger> = OnceCell::new();impl Logger {pub fn global() -> &'static Logger {INSTANCE.get().expect("logger is not initialized")}fn from_cli(args: env::Args) -> Result<Logger, std::io::Error> {// ...}}fn main() {let logger = Logger::from_cli(env::args()).unwrap();INSTANCE.set(logger).unwrap();// 之后就统一使用`Logger::global()`}
延迟创建方式
use std::{sync::Mutex, collections::HashMap};use once_cell::sync::Lazy;static GLOBAL_DATA: Lazy<Mutex<HashMap<i32, String>>> = Lazy::new(|| {let mut m = HashMap::new();m.insert(13, "Spica".to_string());m.insert(74, "Hoyten".to_string());Mutex::new(m)});fn main() {println!("{:?}", GLOBAL_DATA.lock().unwrap());}
