gpt4 book ai didi

rust - 如何在不变成FnOnce的情况下将共享变量从 rust Fn中删除?

转载 作者:行者123 更新时间:2023-12-03 11:36:20 24 4
gpt4 key购买 nike

我在下面实现了一个示例代理服务器,但尝试尝试一下,可能无法弄清楚如何将client从封闭中取出,以便可以共享它。如果我将其取出并删除move,则它将无法编译,因为闭包可能会超过client的生命周期。如果我继续前进,那就是FnOnce而不是Fn。我如何举起client以便可以共享并延长其生存期,以便编译器意识到它一直存在直到应用程序终止?
cargo.toml

[dependencies]
tokio = { version = "0.2", features = ["full"] }
reqwest = { version = "0.10", features = ["json"] }
warp = "0.2.5"
env_logger = "0.8.2"
serde_json = "1.0.61"
futures = "0.3.8"
use serde_json::Value;
use std::collections::HashMap;
use warp::{Filter, http::Method};

#[tokio::main]
async fn main() {
env_logger::init();
let log = warp::log("webserver::proxy");

let cors = warp::cors()
.allow_any_origin()
.allow_header("content-type")
.allow_methods(&[Method::GET, Method::POST, Method::DELETE]);

let signup_route = warp::post()
.and(warp::path("signup"))
.and(warp::path::end())
.and(warp::body::content_length_limit(1024 * 16))
.and(warp::body::json())
.and_then(|body: HashMap<String, Value>| async move {
// How do I move token and client out of this closure to share it?
let token = std::env::var_os("TOKEN").unwrap().into_string().unwrap();
let client = reqwest::Client::new();
return match client.post("https://api.example.com/api")
.header("Authorization", &token)
.header("Content-Type", "application/json")
.json(&body)
.send().await {
Ok(x) => {
let status = x.status();
let json = x.json::<HashMap<String, Value>>().await;
return match json {
Ok(j) => Ok(warp::reply::with_status(warp::reply::json(&j), status)),
Err(_) => Err(warp::reject()),
}
},
Err(_) => Err(warp::reject()),
};
});

let option_route = warp::options().map(warp::reply);
let routes = signup_route.or(option_route).with(cors).with(log);

warp::serve(routes)
.run(([127, 0, 0, 1], 3030))
.await;
}

最佳答案

您需要将客户端和 token 发送到warp,后者将它们运送到不同的线程中(就编译器而言),这些线程可能会超过保存它们的值。这就是为什么编译器不允许闭包捕获对在其外部定义的clienttoken的引用。
相反,您需要对这些值进行堆分配,然后将reference-counted smart pointer移至闭包中。这样就可以吃蛋糕了:您拥有一个拥有值的move闭包,拥有的“值”只是一个指针,并且拥有该指针的另一个副本,可通过克隆Arc获得。必须对内部闭包执行类似的转换,出于相同的原因,该闭包必须变为move

use serde_json::Value;
use std::collections::HashMap;
use std::sync::Arc;
use warp::{http::Method, Filter};

#[tokio::main]
async fn main() {
env_logger::init();
let log = warp::log("webserver::proxy");

let cors = warp::cors()
.allow_any_origin()
.allow_header("content-type")
.allow_methods(&[Method::GET, Method::POST, Method::DELETE]);

let client = Arc::new(reqwest::Client::new());
let client_shared = Arc::clone(&client);

let token = Arc::new(std::env::var_os("TOKEN").unwrap().into_string().unwrap());
let token_shared = Arc::clone(&token);

let signup_route = warp::post()
.and(warp::path("signup"))
.and(warp::path::end())
.and(warp::body::content_length_limit(1024 * 16))
.and(warp::body::json())
.and_then(move |body: HashMap<String, Value>| {
let client_shared = Arc::clone(&client_shared);
let token_shared = Arc::clone(&token_shared);
async move {
return match client_shared
.post("https://api.example.com/api")
.header("Authorization", token_shared.as_str())
.header("Content-Type", "application/json")
.json(&body)
.send()
.await
{
Ok(x) => {
let status = x.status();
let json = x.json::<HashMap<String, Value>>().await;
return match json {
Ok(j) => Ok(warp::reply::with_status(warp::reply::json(&j), status)),
Err(_) => Err(warp::reject()),
};
}
Err(_) => Err(warp::reject()),
};
}
});

let option_route = warp::options().map(warp::reply);
let routes = signup_route.or(option_route).with(cors).with(log);

warp::serve(routes).run(([127, 0, 0, 1], 3030)).await;
}

关于rust - 如何在不变成FnOnce的情况下将共享变量从 rust Fn中删除?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65767979/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com