b1zzu
b1zzu

Reputation: 380

Type mismatch in function arguments

I'm trying to write this small piece of code but I can't get it work. I have a very little experience in Rust, especially with lifetimes.

I have reproduced the error in a smaller script:

fn main() {
    let app = App {
        name: &String::from("Davide"),
    };
    app.run();
}

struct App<'a> {
    name: &'a String,
}

impl<'a> App<'a> {
    fn run(self) {
        let result = App::validator_1(App::validator_2(App::box_command()))(self);
        println!("{}", result)
    }

    fn validator_1(next: Box<Fn(App) -> String>) -> Box<Fn(App) -> String> {
        Box::new(move |app: App| -> String { next(app) })
    }

    fn validator_2(next: Box<Fn(App) -> String>) -> Box<Fn(App) -> String> {
        Box::new(move |app: App| -> String { next(app) })
    }

    fn box_command() -> Box<Fn(App) -> String> {
        Box::new(App::command)
    }

    fn command(self) -> String {
        format!("Hello {}!", self.name)
    }
}

When I compile it, I get this error:

error[E0631]: type mismatch in function arguments
  --> src/main.rs:27:9
   |
27 |         Box::new(App::command)
   |         ^^^^^^^^^^^^^^^^^^^^^^ expected signature of `for<'r> fn(App<'r>) -> _`
...
30 |     fn command(self) -> String {
   |     -------------------------- found signature of `fn(App<'_>) -> _`
   |
   = note: required for the cast to the object type `for<'r> std::ops::Fn(App<'r>) -> std::string::String`

error[E0271]: type mismatch resolving `for<'r> <fn(App<'_>) -> std::string::String {App<'_>::command} as std::ops::FnOnce<(App<'r>,)>>::Output == std::string::String`
  --> src/main.rs:27:9
   |
27 |         Box::new(App::command)
   |         ^^^^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter, found concrete lifetime
   |
   = note: required for the cast to the object type `for<'r> std::ops::Fn(App<'r>) -> std::string::String`

I understand that the problem is somehow related to the lifetime of name in App but I don't know how to fix it.

Upvotes: 1

Views: 1664

Answers (1)

Kajal Sinha
Kajal Sinha

Reputation: 1575

The signature of the command function does not match with what box_command is expected to return.

box_command should have the following body:

fn box_command() -> Box<Fn(App) -> String> {
    Box::new(move |app: App| -> String { app.command() })
}

The compiler is expecting an invocation which returns a String. The above change will allow self from the following statement to be passed as the app argument. Thus app.command() satisfies the entire flow and returns String from the invocation chain.

let result = App::validator_1(App::validator_2(App::box_command()))(self);

Upvotes: 3

Related Questions