Переменная, которая выбирает между двумя асинхронными функциями в несовместимых с ржавчиной типах arm

#rust #rust-actix #rust-async-std

Вопрос:

У меня есть переменная, которая будет контролировать, какая функция является поведением моего веб-приложения по умолчанию, но обе функции есть, и она мне не позволит, потому что они разные. async Что-то вроде этого воспроизводит ту же ошибку: https://play.rust-lang.org/?version=stableamp;mode=debugamp;edition=2018amp;gist=db0269ef4852a94438e6d4925ca83d3b

Теперь мои вопросы таковы:

  • Как мне решить эту проблему, чтобы совпадение работало?
  • Есть ли лучший способ программно настроить поведение сервера по умолчанию в actix на основе флагов пользовательского интерфейса командной строки? Для контекста это более или менее то, что у меня есть:

main.rs

 // Matches comes from the command line
let a = match matches.occurrences_of("default"){
        1 => handlers::forward,
        _ => handlers::resource_not_found,
    };

... setting up db, auth etc

HttpServer::new(move || {
            App::new()
            ... lots of routes 
            .default_service(web::route().to(a))
 

handlers.rs

 
pub async fn resource_not_found(
) -> Result<HttpResponse, Error> {
   Ok(HttpResponse::NotFound().body("Resource does not exist"))
}
pub async fn forward(
) -> Result<HttpResponse, Error> {
   Ok(HttpResponse::Ok().body("Resource does exist"))
}
 

Ответ №1:

Как мне решить эту проблему, чтобы совпадение работало

Вы можете создать два замыкания, которые оба возвращают упакованное будущее, и принудить их к указателю функции:

 use std::pin::Pin;
use std::future::Future;

let a: fn() -> Pin<Box<dyn Future<Output = Result<HttpResponse, Error>>>> =
    match matches.occurrences_of("default") {
        1 => || Box::pin(handlers::forward()),
        _ => || Box::pin(handlers::resource_not_found()),
    };
 

Если функции действительно настолько просты, то вы можете избежать бокса и вернуться std::future::Ready :

 use std::pin::Pin;
use std::future::{Future, Ready, ready};

let a: fn() -> Ready<Result<HttpResponse, Error>> =
    match matches.occurrences_of("default") {
        1 => || handlers::forward,
        _ => || handlers::resource_not_found,
    };

// handlers.rs

pub fn resource_not_found(
) -> Ready<Result<HttpResponse, Error>> {
   ready(Ok(HttpResponse::NotFound().body("Resource does not exist")))
}

pub fn forward(
) -> Ready<Result<HttpResponse, Error>> {
   ready(Ok(HttpResponse::Ok().body("Resource does exist")))
}
 

Есть ли лучший способ программно настроить поведение сервера по умолчанию в actix на основе флагов пользовательского интерфейса командной строки

Вы могли бы выполнить сопоставление внутри нового обработчика, а не снаружи:

 let x = matches.occurrences_of("default");
let a = move || async move {
    match x {
        1 => handlers::forward().await,
        _ => handlers::resource_not_found().await,
    }
};
 

Теперь вместо дополнительного распределения и динамической отправки на вызов вам просто нужно сопоставить целое число.