The following code fails to compile:
fn foo<'a, F: Fn() -> &'a str>(vec: Vec<i32>, fun: F) -> impl Iterator<Item = i32> {
println!("{}", fun());
vec.into_iter()
}
fn main() {
let s = "hello, world!".to_string();
let iter = foo(vec![1, 2, 3], || &s);
drop(s);
for x in iter {
println!("{}", x);
}
}
error[E0505]: cannot move out of `s` because it is borrowed
--> src/main.rs:9:10
|
8 | let iter = foo(vec![1, 2, 3], || &s);
| -- - borrow occurs due to use in closure
| |
| borrow of `s` occurs here
9 | drop(s);
| ^ move out of `s` occurs here
10 |
11 | for x in iter {
| ---- borrow later used here
It compiles if I replace foo's signature with
fn foo<'a, F: Fn() -> &'a str>(vec: Vec<i32>, fun: F) -> <Vec<i32> as IntoIterator>::IntoIter {
// ...
}
It makes me believe that impl Trait types are borrow-checked more conservatively: the compiler assumes that the returned object captures fun even though it doesn't.
However, this interesting example compiles fine:
fn foo(s: &str) -> impl Iterator<Item = i32> {
println!("{}", s);
vec![1, 2, 3].into_iter()
}
fn main() {
let s = "hello, world!".to_string();
let iter = foo(&s);
drop(s);
for x in iter {
println!("{}", x);
}
}
Here the compiler seems not to assume that the returned impl Iterator<Item = i32> borrows s.
How exactly are returned impl Trait types borrow-checked? When are they assumed to borrow other function arguments, like in the first case? When are they assumed not to, like in the latter case?