先用一小段代碼輔助說明結論(涉及多線程、多個可變引用下的實現)
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>> {
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()
}
}
}
- 用
Option<...>作為靜態變量來存儲單例對象的原始全局指針,用get_or_insert_with方法來初始化單例對象 - 最嚴謹的方法是用
Arc<Mutex<T>>或者Arc<RwLock<T>>來持有單例對象;如果不需要單例對象的可變引用,直接用Arc<T>即可;如果是單線程程序,Arc可以可用Rc替代
為什么不用Box而是Arc/Rc?
Box表示唯一的指針引用,不能clone。單例對象是要被多處代碼所引用的,Box<T>只能move不能clone,所以根本無法實現將一個Box<T>作為共享指針。
不需要可變引用的情況
如果不需要可變引用,那就沒有必要使用Mutex或者RwLock了。可以返回一個Arc<T>或者&'static T
pub fn get_instance() -> Arc<Point> {
static mut POINT: Option<Arc<Point>> = None;
unsafe {// Rust中使用可變靜態變量都是unsafe的
POINT.get_or_insert_with(|| {
// 初始化單例對象的代碼
Arc::new(Point {x: 0, y: 0})
}).clone()
}
}
// 返回&'static Point
pub fn get_instance() -> &'staic Point {
static mut POINT: Option<Arc<Point>> = None;
unsafe {// Rust中使用可變靜態變量都是unsafe的
POINT.get_or_insert_with(|| {
// 初始化單例對象的代碼
Arc::new(Point {x: 0, y: 0})
});
POINT.as_ref().unwrap()
}
}
