在Rust中,全局变量通过关键字static声明。这些变量在程序执行期间一直存在。默认情况下,对不可变static的访问是安全的,但对可变的则需要使用unsafe,因为编译器无法保证不存在线程竞争。
为了安全地访问可变全局变量,会使用特殊的包装类型:Mutex、RwLock、Atomic*类型或外部的crate(如lazy_static、once_cell)。初始化是"惰性"的,即在第一次访问时延迟创建对象。
示例:
static COUNTER: AtomicUsize = AtomicUsize::new(0); static ref CONFIG: Config = read_config(); // 通过lazy_static或once_cell
是否可以在没有特殊类型的情况下声明可变全局变量,如果它只会在一个线程中使用?需要写 unsafe 吗?
回答:
编译器会要求在任何修改全局变量时使用unsafe,即使逻辑是单线程的。这是对所有static mut的普遍要求。只有当变量被封装在同步结构中(例如Mutex、原子等),编译器才会允许安全访问。
static mut VALUE: i32 = 0; unsafe { VALUE += 1; }
故事
在web服务中,在初始化全局缓存时使用了普通的static变量和字符串。多个线程同时写入,导致"内存炸弹"和应用程序崩溃,因为出现了线程竞争。
故事
在Rust命令行工具中,修改了没有同步的静态变量,因为"只通过main工作"。后来将代码屏蔽以适应多线程,忘记了全局可变状态,导致了非常难以发现的错误。
故事
在嵌入式程序中,错误地通过函数初始化了static CONFIG,但没有保证该函数将被调用一次,从而导致代码的某些部分访问未初始化的配置(空引用)。