用Option<…>作为静态变量来存储单例对象的原始全局指针,用get_or_insert_with方法来初始化单例对象
    最严谨的方法是用 Arc> 或者Arc>来持有单例对象;如果不需要单例对象的可变引用,直接用Arc即可;如果是单线程程序,Arc可以可用Rc替代

    1. use std::sync::Arc;
    2. use std::sync::Mutex;
    3. struct Point {
    4. pub x: u32,
    5. pub y: u32,
    6. }
    7. impl Point {
    8. pub fn get_instance() -> Arc<Mutex<Point>> {
    9. // 全局变量作为Option类型,get_or_insert_with在判断自己是否为None时,
    10. // 也可能有多线程竞争的问题,最安全的方法是给Option也套一个锁。
    11. // 可以使用第三方库once_cell实现更简单的写法
    12. static mut POINT: Option<Arc<Mutex<Point>>> = None;
    13. unsafe {
    14. // Rust中使用可变静态变量都是unsafe的
    15. POINT.get_or_insert_with(|| {
    16. // 初始化单例对象的代码
    17. Arc::new(Mutex::new(Point {x: 0, y: 0}))
    18. }).clone()
    19. }
    20. }
    21. }

    once_cell提供了unsync::OnceCell和sync::OnceCell这两种Cell(字面意思,前者用于单线程,后者用于多线程),用来存储堆上的信息,并且具有最多只能赋值一次的特性

    1. use std::{env, io};
    2. use once_cell::sync::OnceCell;
    3. #[derive(Debug)]
    4. pub struct Logger {
    5. // ...
    6. }
    7. static INSTANCE: OnceCell<Logger> = OnceCell::new();
    8. impl Logger {
    9. pub fn global() -> &'static Logger {
    10. INSTANCE.get().expect("logger is not initialized")
    11. }
    12. fn from_cli(args: env::Args) -> Result<Logger, std::io::Error> {
    13. // ...
    14. }
    15. }
    16. fn main() {
    17. let logger = Logger::from_cli(env::args()).unwrap();
    18. INSTANCE.set(logger).unwrap();
    19. // 之后就统一使用`Logger::global()`
    20. }

    延迟创建方式

    1. use std::{sync::Mutex, collections::HashMap};
    2. use once_cell::sync::Lazy;
    3. static GLOBAL_DATA: Lazy<Mutex<HashMap<i32, String>>> = Lazy::new(|| {
    4. let mut m = HashMap::new();
    5. m.insert(13, "Spica".to_string());
    6. m.insert(74, "Hoyten".to_string());
    7. Mutex::new(m)
    8. });
    9. fn main() {
    10. println!("{:?}", GLOBAL_DATA.lock().unwrap());
    11. }