主要观点:
- 介绍了
lazy_static和once_cell在 Rust 中的使用及差异,Rust 1.70 和 1.80 标准库新增了一次性初始化值的能力。 - 大多数大型项目会使用这两个库的其中之一,
lazy_static最早在 2014 年 11 月发布,once_cell在 2018 年 8 月发布。 - 讨论了两者的工作原理、特点及差异,包括线程安全和非线程安全版本等。
- 认为在大多数情况下应优先使用
once_cell而非lazy_static,lazy_static是宏,存在一些问题如代码风格怪异、影响dead_codelint 等。 - 介绍了
once_cell的Lazy和OnceCell类型的特点及使用场景。 - 指出
lazy_static存在一些潜在问题,如支持自旋锁阻塞、可对生成的类型实现 trait 等。 - 提到在异步环境中,上述三种实现的懒初始化可能存在问题,Tokio 有异步版本的
OnceCell。 - 强调懒初始化虽能解决一些问题,但并非首选,有时使用普通
static更简单易调试,且应避免使用全局变量。
关键信息:
lazy_static最早发布,通过宏在模块作用域声明静态变量,如lazy_static! { static ref ENTITIES: Mutex<HashMap<String, u32>> = Mutex::default(); }。once_cell较晚出现,无需宏,如static ENTITIES: Lazy<Mutex<HashMap<String, u32>>> = Lazy::new(Mutex::default);,还有OnceCell类型可在值获取处进行初始化代码放置。- Rust 1.70 标准库稳定了自己的懒初始化容器,与
once_cell类似但名称稍有不同,1.80 标准库的LazyLock类型也已稳定。 once_cell的Lazy可在非全局结构体和枚举中使用,OnceCell可单独指定初始化代码,有线程安全和非线程安全版本。lazy_static存在代码风格怪异、影响dead_codelint、生成的类型易混淆等问题。- 在异步环境中,懒初始化可能有问题,Tokio 有异步版本的
OnceCell。
重要细节:
lazy_static生成的代码包含struct LAZY_STRING和static变量LAZY_STRING,内部类型隐藏且值存储在另一个静态变量中。lazy_static的spin特性可能导致意外使用自旋锁阻塞。lazy_static可用于非Send值,once_cell::sync类型要求Send + Sync。- 全局变量可能带来问题,应尽量避免使用,可通过传递参数或成员变量代替。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用。你还可以使用@来通知其他用户。