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