Каков механизм преобразования функции в трейт в Rust?

пример из actix-web выглядит следующим образом:

use actix_web::{web, App, Responder, HttpServer};

async fn index() -> impl Responder {
    "Hello world!"
}

#[actix_rt::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new().service(
            web::scope("/app").route("/index.html", web::get().to(index)),
        )
    })
    .bind("127.0.0.1:8088")?
    .run()
    .await
}

Мой вопрос касается того, как оператор to(index) работает в Rust.

Глядя на исходный код для to, мы видим :

pub fn to<F, T, R, U>(mut self, handler: F) -> Self
where
    F: Factory<T, R, U>,
// --- snip

Где Factory определяется как:

pub trait Factory<T, R, O>: Clone + 'static
where
    R: Future<Output = O>,
    O: Responder,
{
    fn call(&self, param: T) -> R;
}

Каков механизм преобразования функции async fn index() -> impl Responder в Factory<T, R, O>?


person dav_i    schedule 10.09.2020    source источник
comment
Это, действительно, хороший вопрос. Я жду.   -  person Netwave    schedule 10.09.2020


Ответы (1)


Сразу после ваш фрагмент:

impl<F, R, O> Factory<(), R, O> for F
where
    F: Fn() -> R + Clone + 'static,
    R: Future<Output = O>,
    O: Responder,
{
    fn call(&self, _: ()) -> R {
        (self)()
    }
}

Это можно прочитать так: если тип F реализует Fn() -> Future<Output = impl Responder> + ..., то он также реализует Factory<(), _, _>.

И async fn — это синтаксический сахар для функции, которая возвращает Future некоторого вида (и может использовать .await внутри), поэтому async fn index() -> impl Responder реализует Fn() -> impl Future<Output = impl Responder>, поэтому она также реализует Factory<(), _, _>.

person rodrigo    schedule 10.09.2020
comment
Также исправление жаргона: в опубликованном коде нет конверсии, вместо этого есть ограничение: F необходимо реализовать указанный признак, но его личность не меняется. - person Masklinn; 10.09.2020