Ferrugem: E0562 ao implementar o traço genérico

Sep 05 2020

Estou testando o Rust e ❤️ até agora.

Mas atualmente estou preso a características genéricas :)

Status quo:

Há esta característica que desejo implementar, que não posso modificar:

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

Uma implementação dessa característica na mesma biblioteca é:

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 essa implementação pode ser usada da seguinte maneira:

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

Com o IntoReponsetraço:

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

O que eu quero fazer:

Quero implementar essa característica para que uma estrutura possa ser usada com os tipos mencionados acima.

Eu tentei:

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

Mas isso resulta nos erros:

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> {
   |                                                           ^^^^^^^^^^^^^^^^^

Funciona perfeitamente se eu implementá-lo para um tipo específico, por exemplo

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

mas eu gostaria de manter o de impl Traitalguma forma.

Aguardamos qualquer sugestão.

Obrigado e cumprimentos Thomas

EDITAR:

Continuando com a resposta de @MaxV (obrigado!), Infelizmente isso não funcionou para mim (é por isso que eu não aceitei essa resposta ainda).

Veja este playground

Ao tentar retornar Ok(...)com uma implementação de tipo IntoResponse, recebo o seguinte erro:

  |
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<()>`

embora eu tenha implementado IntoResponsepara Response:

trait IntoResponse{
    fn foo(&self);
}

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

o que estou perdendo?

Respostas

MaxV Sep 05 2020 at 04:16

Nova resposta

Parece que você está procurando por tipos existenciais :

No momento, não é possível retornar um impl Traittipo de uma implementação de característica. Esta é uma grande restrição que este RFC corrige <...>

RFC de tipos existenciais foi mesclado, mas a implementação não estabilizou. Você pode acompanhar o progresso lá .

Resposta original

Você não pode usar impllá, mas pode resolver desta forma:

Parque infantil

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