前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【Rust每周一库】once_cell - 最多初始化一次的cell

【Rust每周一库】once_cell - 最多初始化一次的cell

作者头像
MikeLoveRust
发布于 2020-12-18 08:31:19
发布于 2020-12-18 08:31:19
6.8K00
代码可运行
举报
运行总次数:0
代码可运行

once_cell提供了unsync::OnceCellsync::OnceCell这两种Cell(字面意思,前者用于单线程,后者用于多线程),用来存储堆上的信息,并且具有最多只能赋值一次的特性。API大概是:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
impl<T> OnceCell<T> {
    fn new() -> OnceCell<T> { ... }
    fn set(&self, value: T) -> Result<(), T> { ... }
    fn get(&self) -> Option<&T> { ... }
}

用法

安全的初始化全局变量

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
use std::{env, io};

use once_cell::sync::OnceCell;

#[derive(Debug)]
pub struct Logger {
    // ...
}
static INSTANCE: OnceCell<Logger> = OnceCell::new();

impl Logger {
    pub fn global() -> &'static Logger {
        INSTANCE.get().expect("logger is not initialized")
    }

    fn from_cli(args: env::Args) -> Result<Logger, std::io::Error> {
       // ...
    }
}

fn main() {
    let logger = Logger::from_cli(env::args()).unwrap();
    INSTANCE.set(logger).unwrap();
    // 之后就统一使用`Logger::global()`
}

Lazy产生全局变量

包中提供了Lazy,(也分sync和unsync版)可以起到类似之前提到过的lazy_static的作用——在第一次使用的时候产生一个动态的全局静态变量

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
use std::{sync::Mutex, collections::HashMap};
use once_cell::sync::Lazy;

static GLOBAL_DATA: Lazy<Mutex<HashMap<i32, String>>> = Lazy::new(|| {
    let mut m = HashMap::new();
    m.insert(13, "Spica".to_string());
    m.insert(74, "Hoyten".to_string());
    Mutex::new(m)
});

fn main() {
    println!("{:?}", GLOBAL_DATA.lock().unwrap());
}

其中的好处就是不需要神奇的宏魔法了,这也是近期tokio使用它取代了之前的lazy_static的原因:https://github.com/tokio-rs/tokio/pull/3187

比起lazy_static,我们还支持局部变量

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
use once_cell::unsync::Lazy;

fn main() {
    let ctx = vec![1, 2, 3];
    let thunk = Lazy::new(|| {
        ctx.iter().sum::<i32>()
    });
    assert_eq!(*thunk, 6);
}

而且使用OnceCell还可以嵌入到结构体中

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
use std::{fs, path::PathBuf};

use once_cell::unsync::OnceCell;

struct Ctx {
    config_path: PathBuf,
    config: OnceCell<String>,
}

impl Ctx {
    pub fn get_config(&self) -> Result<&str, std::io::Error> {
        let cfg = self.config.get_or_try_init(|| {
            fs::read_to_string(&self.config_path)
        })?;
        Ok(cfg.as_str())
    }
}

因此可以用它来构建其它更复杂的东西!

小结

那大家可能好奇它和lazy_static究竟有什么区别。小结一下就是:

  • 就像上边的例子展现的,once_cell更灵活易用,也没用宏魔法
  • lazy_static可以支持no_std

不过Lazy往上游提交pr也有很长时间了,有兴趣的可以去围观下https://github.com/rust-lang/rfcs/pull/2788

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-12-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Rust语言学习交流 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档