I would like to declare a lifetime for a closure in Rust, but I can't find a way to add a lifetime declaration.
use std::str::SplitWhitespace;
pub struct ParserError {
pub message: String,
}
fn missing_token(line_no: usize) -> ParserError {
ParserError {
message: format!("Missing token on line {}", line_no),
}
}
fn process_string(line: &str, line_number: usize) -> Result<(), ParserError> {
let mut tokens = line.split_whitespace();
match try!(tokens.next().ok_or(missing_token(line_number))) {
"hi" => println!("hi"),
_ => println!("Something else"),
}
// The following code gives "cannot infer appropriate lifetime.....
// let nt = |t: &mut SplitWhitespace| t.next().ok_or(missing_token(line_number));
// match try!(nt(&mut tokens)) {
// "there" => println!("there"),
// _ => println!("_"),
// }
// Where should I declare the lifetime 'a?
// let nt = |t: &'a mut SplitWhitespace| t.next().ok_or(missing_token(line_number));
// match try!(nt(&mut tokens)) {
// "there" => println!("there"),
// _ => println!("_"),
// }
return Ok(());
}
fn main() {
process_string("Hi there", 5).ok().expect("Error!!!");
process_string("", 5).ok().expect("Error!!! 2");
}
Complete sample code on the playground.
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> src/main.rs:22:42
|
22 | let nt = |t: &mut SplitWhitespace| t.next().ok_or(missing_token(line_number));
| ^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 22:14...
--> src/main.rs:22:14
|
22 | let nt = |t: &mut SplitWhitespace| t.next().ok_or(missing_token(line_number));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...so that the types are compatible:
expected std::iter::Iterator
found std::iter::Iterator
note: but, the lifetime must be valid for the call at 23:16...
--> src/main.rs:23:16
|
23 | match try!(nt(&mut tokens)) {
| ^^^^^^^^^^^^^^^
note: ...so type `std::result::Result<&str, ParserError>` of expression is valid during the expression
--> src/main.rs:23:16
|
23 | match try!(nt(&mut tokens)) {
| ^^^^^^^^^^^^^^^
How can I declare the lifetime 'a
for this closure?
I don't know how to answer your question, but there are two ways to solve the problem:
The easiest one is to let the closure reference the iterator directly.
If you don't actually need do anything else with
tokens
afterwards, just do:The other solution is to write a function that emulates what the closure is doing and call that instead.
As originally pointed out by DK., you can use a function to apply extra constraints to a closure's arguments and return values:
This gives you the full abilities of the
where
clause; in this case you can use higher-ranked trait bounds (for <...>
) to say that the closure must return a reference of the same lifetime as the argument.Ultimately, this is caused due to limitations in Rust's type inference. Specifically, if a closure is passed immediately to a function that uses it, the compiler can infer what the argument and return types are. Unfortunately, when it is stored in a variable before being used, the compiler does not perform the same level of inference.
This workaround works because it immediately passes the closure to a function, nailing down the types and lifetime references.
The
&mut SplitWhitespace
is actually a&'b mut SplitWhitespace<'a>
. The relevant lifetime here is the'a
, as it specifies how long the string slices thatnext
returns live. Since you applied thesplit_whitespace
function on yourline
argument, you need to set'a
to the same lifetime that theline
argument has.So as a first step you add a lifetime to
line
:and then you add the lifetime to the type in your closure:
Note that while this answers your question, the correct solution to your Problem is @A.B.'s solution.