借值还不够活?
Borrowed value does not live enough?
这是 的延续,制作了一个新的 Q 以更好地呈现。
我用 Mutex 做了一个最小的 main
,但现在 test_for_closure
做了 not live long enough
并且是 dropped here while still borrowed
。多么美妙的旅程! :)
Rust 游乐场link: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 响应中发回“当前”值?
有两个问题,首先,Body
只实现了 From<&'static str>
,但是给定的 &str
绑定到 MutexGuard
上的生命周期,因此 Body::from
调用失败并出现生命周期错误。您可以通过 foo.clone()
.
解决此问题
第二个问题是关于多个嵌套范围的,这需要在 Arc<Mutex<String>>
和 service_fn
闭包上增加 clone()
和 move
。以下编译:
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(())
}
这是
我用 Mutex 做了一个最小的 main
,但现在 test_for_closure
做了 not live long enough
并且是 dropped here while still borrowed
。多么美妙的旅程! :)
Rust 游乐场link: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 响应中发回“当前”值?
有两个问题,首先,Body
只实现了 From<&'static str>
,但是给定的 &str
绑定到 MutexGuard
上的生命周期,因此 Body::from
调用失败并出现生命周期错误。您可以通过 foo.clone()
.
第二个问题是关于多个嵌套范围的,这需要在 Arc<Mutex<String>>
和 service_fn
闭包上增加 clone()
和 move
。以下编译:
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(())
}