直接回答:static 必须在编译期完成初始化(初始值要求是 const 表达式),所以 HashMap::new() 这类运行期值不能直接赋给 static。运行期才能初始化的全局值需要懒初始化机制:生态里有 lazy_static 宏和 once_cell;标准库 1.70 起稳定了 OnceLock,1.80 又加入 LazyLock,新项目应直接用标准库。
展开解析:OnceLock<T> 内部用原子操作保证 get_or_init 全局只成功初始化一次,多线程访问安全;LazyLock<T> 把初始化闭包绑定进类型,首次解引用时自动初始化,写法更简洁。需要可变全局状态时用 static X: Mutex<T> 包一层,而不是 static mut——后者多线程访问即数据竞争,Rust 2024 版甚至对取其引用直接报错。全局状态还会拖累测试的可并行性,能注入依赖时优先依赖注入。
static CONFIG: LazyLock<String> =
LazyLock::new(|| std::env::var("APP_ENV").unwrap_or_default());
static POOL: OnceLock<DbPool> = OnceLock::new();
fn pool() -> &'static DbPool { POOL.get_or_init(connect_db) }
追问方向:OnceLock 与 LazyLock 怎么选?为什么 static mut 被弃用?全局状态对单元测试有什么影响?
(约 560 字)