使用 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 非常適合此目的。