使用 mut static 的安全靜態 mut

可變全域性項(稱為 static mut,突出顯示其使用中涉及的固有矛盾)是不安全的,因為編譯器很難確保它們被恰當地使用。

但是,在資料周圍引入互斥鎖允許記憶體安全的可變全域性變數。但這並不意味著它們在邏輯上是安全的!

#[macro_use]
extern crate lazy_static;
extern crate mut_static;

use mut_static::MutStatic;

pub struct MyStruct { value: usize }

impl MyStruct {
    pub fn new(v: usize) -> Self{
        MyStruct { value: v }
    }
    pub fn getvalue(&self) -> usize { self.value }
    pub fn setvalue(&mut self, v: usize) { self.value = v }
}

lazy_static! {
    static ref MY_GLOBAL_STATE: MutStatic<MyStruct> = MutStatic::new();
}

fn main() {
    // Here, I call .set on the MutStatic to put data inside it.
    // This can fail.
    MY_GLOBAL_STATE.set(MyStruct::new(0)).unwrap();
    {
        // Using the global state immutably is easy...
        println!("Before mut: {}", 
                 MY_GLOBAL_STATE.read().unwrap().getvalue());
    }
    {
         // Using it mutably is too...
         let mut mut_handle = MY_GLOBAL_STATE.write().unwrap();
         mut_handle.setvalue(3);
         println!("Changed value to 3.");
    } 
    {
        // As long as there's a scope change we can get the 
        // immutable version again...
        println!("After mut: {}", 
                 MY_GLOBAL_STATE.read().unwrap().getvalue());
    }
    {
        // But beware! Anything can change global state!
        foo();
        println!("After foo: {}", 
                 MY_GLOBAL_STATE.read().unwrap().getvalue());
    }
 
}

// Note that foo takes no parameters
fn foo() {
    let val;
    {
        val = MY_GLOBAL_STATE.read().unwrap().getvalue();
    }
    {
        let mut mut_handle = 
            MY_GLOBAL_STATE.write().unwrap();
        mut_handle.setvalue(val + 1);
    }
}

此程式碼生成輸出:

Before mut: 0
Changed value to 3.
After mut: 3
After foo: 4

這通常不會發生在 Rust 中。foo() 並沒有對任何東西進行可變引用,因此它不應該突變任何東西,但它確實如此。這可能導致很難除錯邏輯錯誤。

另一方面,這有時正是你想要的。例如,許多遊戲引擎需要全域性快取影象和其他懶惰載入的資源(或使用其他複雜的載入策略) - MutStatic 非常適合此目的。