lazy_static的延迟初始化?

Lazy initialisation of lazy_static?

提问人:mike rodent 提问时间:10/6/2023 更新时间:10/6/2023 访问量:69

问:

我已经在以下方面取得了一些成功:lazy_static

static ref WORD_COUNT_REPORTING_STEP_MUTEX: Arc<Mutex<usize>> = Arc::new(Mutex::new(0));
static ref INDEX_NAME: RwLock<String> = RwLock::new("".to_string());
static ref LANGUAGE_DETECTOR: LanguageDetector = LanguageDetectorBuilder::from_all_languages().with_preloaded_language_models().build();

但是我真的在为看似相当简单的模式挠头:将某种类型设置为,然后在发现确实是 .如果发现 是 ,则跳过初始化。在初始化块之后,获取 和 。Option<T>NoneOptionNoneOptionSomeOptionunwrap()

注意,这里的类型是 .reqwest::blocking::client::Client

到目前为止,我有:

lazy_static! {
    static ref REQWEST_CLIENT_OPTION: Option<Client> = None;
}

然后,在一个函数中:

...
match &*REQWEST_CLIENT_OPTION {
    Some(reqwest_client) => {
        info!("reqwest_client_option currently non-None");
    },
    None => {
        info!("reqwest_client_option currently None");
        
        // configuration and build of the client
        let es_path = r#"D:\apps\ElasticSearch\elasticsearch-8.6.2\config"#;
        set_var("ES_PATH_CONF", &es_path); // from crate tmp_env
        let mut buf = Vec::new();
        let cert_path = format!(r#"{es_path}\certs\http_ca.crt"#);
        let mut cert_file = File::open(cert_path).expect("problem opening certificate file");
        cert_file.read_to_end(&mut buf).ok();
        let cert = reqwest::Certificate::from_pem(&buf).expect("problem generating certificate"); // delivers cert OK
        let reqwest_client = Client::builder()
            .add_root_certificate(cert)
            .timeout(std::time::Duration::from_millis(5_000))
            .build().expect("problem building the request client");

        // now I try to set the Option...
        let mut static_client = &*REQWEST_CLIENT_OPTION;
        info!("static_client type {}", utilities::str_type_of(&static_client));
        // static_client type &core::option::Option<reqwest::blocking::client::Client>
        static_client = &Some(reqwest_client)
        // not now possible to check static_client. 
    }
}
let reqwest_client = REQWEST_CLIENT_OPTION.as_ref().unwrap();    
...

以上主要是猜测。毋庸置疑,我已经尝试了无数次涉及 *、& 和类似 .我希望这可能会起作用:let_mut

*static_client = Some(reqwest_client);

...但这失败了:“ ^^^^^^^^^^^^^^ 是一个参考,所以它引用的数据不能写入”。static_client&

至少上面的代码编译正常。
打印“reqwest_client_option当前无”行。
但令我失望的是,最后一行引起了恐慌:

pyo3_runtime.PanicException: called `Option::unwrap()` on a `None` value

注意:我也尝试了一个变体,但遇到了同样的问题。这种结构可能会更优雅。if let Some(reqwest_client) ...

选项类型 lazy-initialization 惰性静态

评论

1赞 Peter Hall 10/6/2023
您可能正在寻找 OnceCell
0赞 aedm 10/6/2023
此外,once_cell::sync::Lazy 有一个简洁的 API。
0赞 Chayim Friedman 10/6/2023
无论如何,您都应该避免使用新项目。lazy_staticonce_cell
0赞 mike rodent 10/6/2023
@ChayimFriedman 想说为什么?PeterHall 的解决方案显然是这项工作的工具。失宠了吗?lazy_static
1赞 Cerberus 10/7/2023
我认为这只是“你不需要它,拥有它的所有功能等等”。once_cell

答:

4赞 Peter Hall 10/6/2023 #1

您可以使用 OnceCell,也可以使用 OnceLock,因为您将其设置为静态。

例如:

use std::sync::OnceLock;
use reqwest::blocking::Client;

static REQWEST_CLIENT: OnceLock<Client> = OnceLock::new();

fn main(){
    let client = REQWEST_CLIENT.get_or_init(|| {
        Client::builder()
            // other options
            .build()
            .expect("problem building the reqwest client")
    });

    // use client
}

评论

0赞 mike rodent 10/6/2023
谢谢,效果很好。这显然是这项工作的最佳工具,但我也只是想知道我试图用 a 和 a 做的事情是否可行。现在我看到 ChayimFriedman 说过“不要使用lazy_static”......但不是为什么。是在弃用的路上还是其他什么?lazy_staticref