Rust 如何将共享变量从生锈的Fn中取出,而不使其变成Fn?

Rust 如何将共享变量从生锈的Fn中取出,而不使其变成Fn?,rust,Rust,我在下面实现了一个示例代理服务器,但尽管我尝试了一下,我还是不知道如何将客户机从闭包中提出来,以便共享它。如果我将其取出并删除移动,那么它将不会编译,因为闭包可能会超过客户端的生命周期。如果我继续移动,那么这是一次Fn,而不是Fn。如何提升客户机,使其可以共享并延长其生存期,从而使编译器意识到它一直存在,直到应用程序终止 货舱 [dependencies] tokio = { version = "0.2", features = ["full"] } r

我在下面实现了一个示例代理服务器,但尽管我尝试了一下,我还是不知道如何将
客户机
从闭包中提出来,以便共享它。如果我将其取出并删除
移动
,那么它将不会编译,因为闭包可能会超过
客户端
的生命周期。如果我继续移动,那么这是一次
Fn
,而不是
Fn
。如何提升
客户机
,使其可以共享并延长其生存期,从而使编译器意识到它一直存在,直到应用程序终止

货舱

[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;
}
使用serde_json::Value;
使用std::collections::HashMap;
使用warp::{Filter,http::Method};
#[tokio::main]
异步fn main(){
环境记录器::init();
让log=warp::log(“webserver::proxy”);
设cors=warp::cors()
.允许任何来源()
.允许_标题(“内容类型”)
.allow_方法(&[Method::GET,Method::POST,Method::DELETE]);
让signup\u route=warp::post()
和(warp::path(“注册”))
.和(warp::path::end())
.和(扭曲::主体::内容\长度\限制(1024*16))
.和(warp::body::json())
然后(| body:HashMap |异步移动{
//如何将令牌和客户端移出此闭包以共享它?
让token=std::env::var_os(“token”).unwrap()转换为_string().unwrap();
让client=reqwest::client::new();
返回匹配的客户端.post(“https://api.example.com/api")
.header(“授权”和令牌)
.header(“内容类型”、“应用程序/json”)
.json(&body)
.send()等待{
Ok(x)=>{
让status=x.status();
让json=x.json::()等待;
返回匹配json{
Ok(j)=>Ok(warp::reply::with_status(warp::reply::json(&j),status)),
Err()=>Err(warp::reject()),
}
},
Err()=>Err(warp::reject()),
};
});
让option_route=warp::options().map(warp::reply);
let routes=注册路由。或(选项路由)。使用(cors)。使用(日志);
翘曲:发球(路线)
.运行([127,0,0,1],3030))
.等待;
}

您需要将客户端和令牌发送到
warp
,然后将它们发送到不同的线程,在那里它们可能(就编译器而言)比保存它们的值更长寿。这就是为什么编译器不允许闭包捕获对
客户机
及其外部定义的
令牌
的引用

相反,您需要对这些值进行堆分配,并将a移到闭包中。这就允许你吃蛋糕:你有一个拥有一个值的
move
闭包,拥有的“value”只是一个指针,你还有另一个指针副本,你可以通过克隆
弧来获得它。必须对内部闭包进行类似的转换,出于相同的原因,内部闭包必须变成
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;
}
使用serde_json::Value;
使用std::collections::HashMap;
使用std::sync::Arc;
使用warp::{http::Method,Filter};
#[tokio::main]
异步fn main(){
环境记录器::init();
让log=warp::log(“webserver::proxy”);
设cors=warp::cors()
.允许任何来源()
.允许_标题(“内容类型”)
.allow_方法(&[Method::GET,Method::POST,Method::DELETE]);
让client=Arc::new(reqwest::client::new());
让客户端共享=Arc::克隆(&client);
让token=Arc::new(std::env::var_os(“token”).unwrap()转换为_string().unwrap());
让token_shared=Arc::clone(&token);
让signup\u route=warp::post()
和(warp::path(“注册”))
.和(warp::path::end())
.和(扭曲::主体::内容\长度\限制(1024*16))
.和(warp::body::json())
.然后(移动| body:HashMap |{
让客户机共享=Arc::克隆(&C)客户机共享;
让令牌共享=Arc::克隆(&令牌共享);
异步移动{
返回匹配客户端\u共享
.post(“https://api.example.com/api")
.header(“授权”,令牌\u共享.as\u str())
.header(“内容类型”、“应用程序/json”)
.json(&body)
.send()
.等待
{
Ok(x)=>{
让status=x.status();
让json=x.json::()等待;
返回匹配json{
Ok(j)=>Ok(warp::reply::with_status(warp::reply::json(&j),status)),
Err()=>Err(warp::reject()),
};
}
Err()=>Err(warp::reject()),
};
}
});
让option_route=warp::options().map(warp::reply);
let routes=注册路由。或(选项路由)。使用(cors)。使用(日志);
服务(路线)。运行([127,0,0,1],3030))。等待;
}