Reputation: 380
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
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