【问题标题】:Borrowed value does not live enough?借来的价值还不够活?
【发布时间】:2021-06-07 22:41:54
【问题描述】:

这是`RefCell<std::string::String>` cannot be shared between threads safely?的延续,为了更好的呈现,做了一个新的Q。

我用互斥锁做了一个最小的main,但现在test_for_closure 做了not live long enough 并且是dropped here while still borrowed。什么骑! :)

Rust 游乐场链接:https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=7bf56545350624e75aafa10524ea59ff

use std::{convert::Infallible, net::SocketAddr};
use std::sync::{Arc, Mutex};

use hyper::{Body, Request, Response, Server, Version};
use hyper::{Method, StatusCode};
use hyper::service::{make_service_fn, service_fn};
// use tokio::sync::Mutex;

#[tokio::main]
use std::{convert::Infallible, net::SocketAddr};
use std::sync::{Arc, Mutex};

use hyper::{Body, Request, Response, Server, Version};
use hyper::service::{make_service_fn, service_fn};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut test: Arc<Mutex<String>> = Arc::new(Mutex::from("Foo".to_string()));
    let mut test_for_closure = Arc::clone(&test);

    let addr = SocketAddr::from(([127, 0, 0, 1], 4321));

    let make_svc = make_service_fn(|_conn| async {
        Ok::<_, Infallible>(service_fn(|req: Request<Body>| async move {
            if req.version() == Version::HTTP_11 {
                let foo = test_for_closure.lock().unwrap();
                Ok(Response::new(Body::from(foo.as_str())))
            } else {
                Err("not HTTP/1.1, abort connection")
            }
        }))
    });

    let server = Server::bind(&addr).serve(make_svc);

    if let Err(e) = server.await {
        eprintln!("server error: {}", e);
    }

    Ok(())
}

考虑到我们最终需要能够在 main 中修改 Arc 的值,但仍然让 hyper 在 HTTP 响应中发回“当前”值,如何解决这个问题?

【问题讨论】:

  • 请将错误粘贴为由三个反引号包围的文本。您的 IDE 的屏幕截图不可搜索、不可编辑,并且对于具有不同字体大小的人或在移动设备上的人来说可能难以阅读。

标签: rust hyper


【解决方案1】:

有两个问题,首先,Body 只实现了From&lt;&amp;'static str&gt;,但给定的&amp;str 绑定到MutexGuard 的生命周期,因此Body::from 调用失败并出现生命周期错误。您可以通过foo.clone() 解决此问题。

第二个问题是关于多个嵌套范围,这将需要在 Arc&lt;Mutex&lt;String&gt;&gt;move 上附加 clone()s 在 service_fn 闭包上。以下编译:

use std::sync::{Arc, Mutex};
use std::{convert::Infallible, net::SocketAddr};

use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Request, Response, Server, Version};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let test: Arc<Mutex<String>> = Arc::new(Mutex::from("Foo".to_string()));

    let addr = SocketAddr::from(([127, 0, 0, 1], 4321));

    let make_svc = make_service_fn(|_conn| {
        let test_for_closure = test.clone();
        let svc_fn = service_fn(move |req: Request<Body>| {
            let test_for_closure = test_for_closure.clone();
            async move {
                if req.version() == Version::HTTP_11 {
                    let foo = test_for_closure.lock().unwrap();
                    Ok(Response::new(Body::from(foo.clone())))
                } else {
                    Err("not HTTP/1.1, abort connection")
                }
            }
        });
        async move { Ok::<_, Infallible>(svc_fn) }
    });

    let server = Server::bind(&addr).serve(make_svc);

    // change the value at will:
    let mut guard = test.lock().unwrap();
    *guard = "Bar".into();
    drop(guard);

    if let Err(e) = server.await {
        eprintln!("server error: {}", e);
    }

    Ok(())
}

Playground

【讨论】:

  • 哇,我还缺少很多东西。非常感谢您的解释!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-07-23
  • 1970-01-01
  • 2019-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多