When you declare closure argument types, there is no syntax to declare a lifetime parameter. And I guess lifetime elision does not apply to closures. Therefore, there seems to be no way to declare the type of a closure that returns a reference.
It compiles if you avoid declaring the type of the closure and depend on type inference. But then you would not be able to assign the closure to a local variable.
fn print_first(list: Vec<String>) {
let x: &str = list
.first()
.map(|s: &String| -> &str &s[]) // ERROR
//.map(|s: &String| &s[]) // ERROR
//.map(|s| -> &str &s[]) // ERROR
//.map(|s| &s[]) // OK
.unwrap_or("");
println!("First element is {}", x);
}
It gives a compiler error and a suggestion that does not make sense.
src/rusttest.rs:4:29: 4:32 error: cannot infer an appropriate lifetime for lifetime parameter 'a in function call due to conflicting requirements
src/rusttest.rs:4 .map(|s: &String| -> &str &s[])
^~~
src/rusttest.rs:1:1: 10:2 help: consider using an explicit lifetime parameter as shown: fn print_first<'a>(list: Vec<String>)
src/rusttest.rs:1 fn print_first(list: Vec<String>) {
src/rusttest.rs:2 let x: &str = list
src/rusttest.rs:3 .first()
src/rusttest.rs:4 .map(|s: &String| -> &str &s[]) // ERROR
src/rusttest.rs:5 //.map(|s: &String| &s[]) // ERROR
src/rusttest.rs:6 //.map(|s| -> &str &s[]) // ERROR
This bug is filed after I asked this question on stack overflow. It may be related to Region inference fails for closure parameter #17004.
Triage: there is still no way to declare lifetime parameters for closures like this today.
Lets throw some ideas out there:
|s: &'a String|<'a> -> &'a str &s[]
<'a>|s: &'a String| -> &'a str &s[]
let closure<'a> = |s: &'a String| -> &'a str &s[];
The last one is a little limited, but may actually be feasible unlike the others.
I just ran into this issue today, trying to return a reference out of a closure that had the same lifetime as one of its arguments. Closures with lifetime, as well and type arguments would definitely be nice to have - if we had them, then I'm pretty sure closures would be just as powerful as functions. There's an RFC to implement them both: https://github.com/rust-lang/rfcs/pull/1650
I played with a similar example today and found a funny workaround.
Just skip type declaration and cast the type in the body of the closure:
|s| -> &str { &(s as &String)[..] }
or even with #![feature(type_ascription)]
|s| -> &str { &(s: &String)[..] }
In this way, type inference can do it's job with a lifetime and the type of the argument is limited by the way of use in the body.
There is another problem related to this one:
error[E0281]: type mismatch: `[closure@src/x.rs:329:50: 335:22 message_type:_]` implements the trait `std::ops::Fn<(_,)>`, but the trait `for<'r> std::ops::Fn<(&'r Message,)>` is required
--> src/x.rs:341:44
|
329 | let filter_by_message_type = |x| {
| __________________________________________________-
330 | | if (x as &Message).get_type() == *message_type {
331 | | Some(x)
332 | | } else {
333 | | None
334 | | }
335 | | };
| |_____________________- implements `std::ops::Fn<(_,)>`
which essentiall prevents using closures for for<'r> Fn(..) -> ...bounded generics
An update: all of the examples given in the bug description do compile today, after being updated for Rust 1.0 syntax:
fn print_first(list: Vec<String>) {
let x: &str = list
.first()
// .map(|s: &String| -> &str { &s[..] }) // OK
// .map(|s: &String| { &s[..] }) // OK
// .map(|s| -> &str { &s[..] }) // OK
.map(|s| { &s[..] }) // OK
.unwrap_or("");
println!("First element is {}", x);
}
fn main() {
print_first(vec![format!("hello"), format!("world")]);
}
(However, what I do not yet know is whether the types we are actually inferring in all of the above cases are what the user expects. See related discussion on #56537...)
Most helpful comment
There is another problem related to this one:
which essentiall prevents using closures for
for<'r> Fn(..) -> ...bounded generics