主要观点:
- 介绍了
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_code
lint 等。 - 介绍了
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_code
lint、生成的类型易混淆等问题。- 在异步环境中,懒初始化可能有问题,Tokio 有异步版本的
OnceCell
。
重要细节:
lazy_static
生成的代码包含struct LAZY_STRING
和static
变量LAZY_STRING
,内部类型隐藏且值存储在另一个静态变量中。lazy_static
的spin
特性可能导致意外使用自旋锁阻塞。lazy_static
可用于非Send
值,once_cell::sync
类型要求Send + Sync
。- 全局变量可能带来问题,应尽量避免使用,可通过传递参数或成员变量代替。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。