使用互斥锁保护的对象

问题描述 投票:0回答:1

我想实现一个惰性静态reqwest::ClientBuilder。注意,这是针对实用程序模块的,因此我有一种感觉,在这种情况下很难避免使用静态。我想构建它一次,然后用它来构建可能的几个

reqwest::Client
(对于不同的超时,这是在客户端构建时设置的)。

所以我有这一行(使用

once_cell::sync::Lazy
):

static CLIENT_BUILDER: Lazy<Mutex<Option<ClientBuilder>>> = Lazy::new(|| Mutex::new(None));

然后我有这个功能:

pub fn get_reqwest_client(timeout: u64 = 5_000) -> Result<Client, Box<dyn std::error::Error>> {
    let mut client_builder_guard = CLIENT_BUILDER.lock().unwrap();
    let client_builder = match client_builder_guard.as_ref() {
        Some(client_builder) => client_builder,
        None => {
            // configuration of builder
            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");
            let _ = cert_file.read_to_end(&mut buf);
            let cert = reqwest::Certificate::from_pem(&buf).expect("problem generating certificate");
            let client_builder = Client::builder()
                .add_root_certificate(cert);
            // setting the Lazy Mutex
            *client_builder_guard = Some(client_builder);
            client_builder_guard.as_ref().unwrap()
        }
    };
    ...

稍后在该函数中:

let client = client_builder.as_ref()
    .timeout(std::time::Duration::from_millis(timeout))
    .build()?;

这会产生错误:

error[E0599]: the method `as_ref` exists for reference `&ClientBuilder`, but its trait bounds were not satisfied
   --> D:\My documents\software projects\EclipseWorkspace\doc_indexer\src\core\utilities\src\lib.rs:154:35
    |
154 |             let client = client_builder.as_ref()
    |                                         ^^^^^^ method cannot be called on `&ClientBuilder` due to unsatisfied trait bounds
    |
   ::: D:\apps\rust\rust_1.70.0\.cargo\registry\src\index.crates.io-6f17d22bba15001f\reqwest-0.11.20\src\blocking\client.rs:69:1
    |
69  | pub struct ClientBuilder {
    | ------------------------ doesn't satisfy `reqwest::blocking::ClientBuilder: AsRef<_>`
    |
    = note: the following trait bounds were not satisfied:
            `reqwest::blocking::ClientBuilder: AsRef<_>`
            which is required by `&reqwest::blocking::ClientBuilder: AsRef<_>`

我也尝试过

*client_builder
client_builder.clone();
甚至
client_builder_guard.as_ref().unwrap()
。似乎没什么作用。

为什么会涉及到

Copy
特质?有解决办法吗?我重新阅读了编译器消息,但不明白(例如,我找到了这个答案,但从表面上看它似乎不适用)。

编辑回复评论
如果我在上面省略

as_ref()
(我已经尝试过),我会得到:

error[E0507]: cannot move out of `*client_builder` which is behind a shared reference
   --> D:\My documents\software projects\EclipseWorkspace\doc_indexer\src\core\utilities\src\lib.rs:153:20
    |
153 |               let client = client_builder
    |  __________________________^
154 | |                 .timeout(std::time::Duration::from_millis(timeout))
    | |___________________________________________________________________^ move occurs because `*client_builder` has type `reqwest::blocking::ClientBuilder`, which does not implement the `Copy` trait
rust static mutex lazy-initialization
1个回答
0
投票

这个问题的答案可能对其他人有帮助,不仅适用于

reqwest::ClientBuilder
,还可能适用于其他“构建器”类型模式。

对于用户4815162342指出的问题的解释是,

ClientBuilder.build
的签名是
pub fn build(self) -> Result<Client>
。因此,它消耗了构建器,这意味着每个客户端都需要一个新的构建器。尝试创建可重用构建器所引起的问题导致了难以理解的编译器消息。

...不幸的是

set_timeout
不是可用于
reqwest::Client
的可选可链接方法之一,因此我选择了静态超时到客户端映射。

© www.soinside.com 2019 - 2024. All rights reserved.