1

I'm trying to declare my routes with closures:

use mongodb::Client;

pub fn get_user_routes(client: Client) -> Router {
    let controller = controller::UserController::new(client);
    let handler = handlers::UserHandler::new(controller);

    router!(
         index:  get    "/"    => move |r: &mut Request| handler.index(r),
         show:   get    "/:id" => move |r: &mut Request| handler.show(r),
    )
}

I get this error and I can't implement the Copy trait for my UserController because the mongodb::Client doesn't implement it (it's an Arc).

error[E0382]: capture of moved value: `handler`
      --> src/api/users/mod.rs:17:57
       |
    16 |         index:  get    "/"    => move |r: &mut Request| handler.index(r),
       |                                  ---------------------- value moved (into closure) here
    17 |         show:   get    "/:id" => move |r: &mut Request| handler.show(r),
       |                                                         ^^^^^^^ value captured here after move
       |
       = note: move occurs because `handler` has type `api::users::handlers::UserHandler`, which does not implement the `Copy` trait

My UserHandler just has a UserController and the UserController, a mongodb::Client.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
NotBad4U
  • 1,502
  • 1
  • 16
  • 23

2 Answers2

3

The router get method takes a handler by value. In Rust, passing by value implies giving up ownership.

By definition, you cannot give up ownership of something twice: it's no longer yours after you gave it up the first time! The only exception to the rule is Copy types, but those are restricted to things like integers and non-mutating references (and references are out because Handler: 'static).

Thus, you need to call .clone() on the handler to be passed. Every time.

A very simple way is to use a block-expression:

let h  = handler;
router!(
    index: get "/"    => { let h = h.clone(); move |r: &mut Request| h.index(r) },
    show:  get "/:id" => { let h = h.clone(); move |r: &mut Request| h.show(r) },
)

this way, you do not have to declare all the clones beforehand.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
1

You can #[derive(Clone)] for your handler, and clone it:

let handler_show = handler.clone();
router!(
     index:  get    "/"    => move |r: &mut Request| handler.index(r),
     show:   get    "/:id" => move |r: &mut Request| handler_show.show(r),
)
Tatsuyuki Ishi
  • 3,883
  • 3
  • 29
  • 41
  • Thank for the response, but unfortunately i'll have more than 2 routes in the future and i think it's not a elegant solution to create a variable for each new routes. – NotBad4U Mar 10 '17 at 09:04