Rust 用 once_cell 管理全局配置与单例连接:初始化只跑一次

test12026-10-224 次阅读

为什么不用 lazy_static

lazy_static 靠宏生成静态变量,类型推导和 IDE 支持都一般。once_cell 提供 Lazy 与 OnceCell,用普通 API 表达一次性初始化,编译报错更友好,也是标准库 once_cell 提案的雏形。

用 Lazy 初始化配置

进程级、启动即确定的全局对象(如配置、日志句柄)适合用 Lazy,第一次访问时才初始化,且只初始化一次。

use once_cell::sync::Lazy;
use std::collections::HashMap;

static CONFIG: Lazy<HashMap<String, String>> = Lazy::new(|| {
    let mut m = HashMap::new();
    m.insert("env".into(), std::env::var("APP_ENV").unwrap_or_else(|_| "dev".into()));
    m.insert("region".into(), "cn-hangzhou".into());
    m
});

fn main() {
    println!("env = {}", CONFIG.get("env").unwrap());
}

用 OnceCell 做一次性的运行时初始化

配置来自外部、不能在编译期确定的对象(比如连接池),用 OnceCell 在运行时第一个请求到来时初始化,后续直接复用,避免每次都建连。

use once_cell::sync::OnceCell;
use std::sync::Mutex;

struct DbPool {
    conns: usize,
}

static POOL: OnceCell<Mutex<DbPool>> = OnceCell::new();

fn pool() -> &'static Mutex<DbPool> {
    POOL.get_or_init(|| {
        // 真实场景里在这里建连接池,只跑一次
        Mutex::new(DbPool { conns: 8 })
    })
}

fn query() -> usize {
    let g = pool().lock().unwrap();
    g.conns
}

关键结论

  • Lazy 适合启动期确定的全局值,OnceCell 适合运行时一次性初始化。
  • 两者都保证初始化只发生一次,且是线程安全的。
  • 比 lazy_static 更贴近未来的标准库写法,类型提示更清晰。
T

test1

文章作者

为什么不用 lazy_static lazy_static 靠宏生成静态变量,类型推导和 IDE 支持都一般。once_...

分类
技术
发布时间
2026-10-22
字数
约 1156 字
阅读
4 次