Rust: E0562 quando si implementa un tratto generico

Sep 05 2020

Sto provando Rust e ❤️ finora.

Ma al momento sono bloccato con tratti generici :)

Status quo:

C'è questo tratto che voglio implementare, che non posso modificare:

pub trait Handler<R, B, E> {
    fn run(&mut self, event: http::Request<B>) -> Result<R, E>;
}

Un'implementazione di quel tratto nella stessa libreria è:

impl<Function, R, B, E> Handler<R, B, E> for Function
where
    Function: FnMut(http::Request<B>) -> Result<R, E>,
{
    fn run(&mut self, event: http::Request<B>) -> Result<R, E> {
        (*self)(event)
    }
}

E questa implementazione può essere utilizzata come segue:

fn handler(req: http::Request<Body>) -> Result<impl IntoResponse, MyError> {
    ...
}

Con il IntoReponsetratto:

pub trait IntoResponse {
    fn into_response(self) -> Response<Body>;
}

Cosa voglio fare:

Voglio implementare quel tratto affinché una struttura possa essere utilizzata con i tipi menzionati sopra.

Provai:

impl Handler<impl IntoResponse, Body, MyError> for GQLHandler {
    fn run(&mut self, req: http::Request<Body>) -> Result<impl IntoResponse, MyError> {
        ...
    }
}

Ma questo si traduce negli errori:

error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
  --> handlers/gql.rs:18:14
   |
18 | impl Handler<impl IntoResponse, Body, NowError> for GQLHandler {
   |              ^^^^^^^^^^^^^^^^^

error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
  --> handlers/gql.rs:19:59
   |
19 |     fn run(&mut self, req: http::Request<Body>) -> Result<impl IntoResponse, NowError> {
   |                                                           ^^^^^^^^^^^^^^^^^

Funziona di causa se lo implemento per un tipo specifico, ad es

impl Handler<http::Response<Body>, Body, NowError> for GQLHandler {
    fn run(&mut self, req: http::Request<Body>) -> Result<http::Response<Body>, NowError> {

ma vorrei mantenere il in impl Traitqualche modo.

In attesa di eventuali suggerimenti.

Grazie e saluti Thomas

MODIFICARE:

Seguendo la risposta di @ MaxV (grazie!), Purtroppo non ha funzionato per me (motivo per cui non ho ancora accettato questa risposta).

Vedi questo parco giochi

Quando provo a tornare Ok(...)con un tipo implementato IntoResponse, ottengo il seguente errore:

  |
3 | impl<T: IntoResponse> Handler<T, Body, MyError> for GQLHandler {
  |      - this type parameter
4 |     fn run(&mut self, req: Request<Body>) -> Result<T, MyError> {
5 |         Ok(Response::<()>::new(()))
  |            ^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `T`, found struct `http::Response`
  |
  = note: expected type parameter `T`
                     found struct `http::Response<()>`

anche se ho implementato IntoResponseper Response:

trait IntoResponse{
    fn foo(&self);
}

impl IntoResponse for Response<()>
{
    fn foo(&self) {}
}

Cosa mi sto perdendo?

Risposte

MaxV Sep 05 2020 at 04:16

Nuova risposta

Sembra che tu stia cercando tipi esistenziali :

Al momento, non è possibile restituire un impl Traittipo da un'implementazione di un tratto. Questa è un'enorme restrizione che questa RFC corregge <...>

I tipi esistenziali RFC sono stati uniti ma l'implementazione non si è stabilizzata. Puoi monitorare i progressi lì .

Risposta originale

Non puoi usarlo implma puoi risolverlo in questo modo:

Terreno di gioco

impl<T: IntoResponse> Handler<T, Body, MyError> for GQLHandler {
    fn run(&mut self, req: http::Request<Body>) -> Result<T, MyError> {
        // ...
    }
}