代码与苦涩

主要观点:

  • 介绍了lazy_staticonce_cell在 Rust 中的使用及差异,Rust 1.70 和 1.80 标准库新增了一次性初始化值的能力。
  • 大多数大型项目会使用这两个库的其中之一,lazy_static最早在 2014 年 11 月发布,once_cell在 2018 年 8 月发布。
  • 讨论了两者的工作原理、特点及差异,包括线程安全和非线程安全版本等。
  • 认为在大多数情况下应优先使用once_cell而非lazy_staticlazy_static是宏,存在一些问题如代码风格怪异、影响dead_code lint 等。
  • 介绍了once_cellLazyOnceCell类型的特点及使用场景。
  • 指出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_cellLazy可在非全局结构体和枚举中使用,OnceCell可单独指定初始化代码,有线程安全和非线程安全版本。
  • lazy_static存在代码风格怪异、影响dead_code lint、生成的类型易混淆等问题。
  • 在异步环境中,懒初始化可能有问题,Tokio 有异步版本的OnceCell

重要细节:

  • lazy_static生成的代码包含struct LAZY_STRINGstatic变量LAZY_STRING,内部类型隐藏且值存储在另一个静态变量中。
  • lazy_staticspin特性可能导致意外使用自旋锁阻塞。
  • lazy_static可用于非Send值,once_cell::sync类型要求Send + Sync
  • 全局变量可能带来问题,应尽量避免使用,可通过传递参数或成员变量代替。
阅读 14
0 条评论