However, I don’t actually understand the difference. The explanation in the RFC is too abstract for me to understand. I tried writing a concrete program that fails where it shouldn’t, playground link. However, all the examples I wrote still pass the borrow checker. Can someone show me an actual example where this fails and the new, more correct use<> syntax passes?
The meaning of + 'long + 'short is the same as + 'long and means that the type can't use lifetime annotations shorter than 'long. I.e. it can't use 'short anywhere.
The meaning of + use<'long, 'short> means that the type can only use the lifetime annotations 'long and 'short. I.e. it can use 'short.
For your case it means that the second lifetime is redundant. Your code might as well be
This means that you can't have search_term be with a longer lifetime than the one on str_iter. But since you can't get search_term out of the iterator as a &str, that doesn't really matter anyway.
error[E0597]: `search_term` does not live long enough
--> src/main.rs:103:36
|
101 | fn fails<'a>(i: impl IntoIterator<Item = &'a str> + 'a) {
| -- lifetime `'a` defined here
102 | let search_term = "error".to_owned();
| ----------- binding `search_term` declared here
103 | let err_lines = filter_strs(i, &search_term);
| ---------------^^^^^^^^^^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `search_term` is borrowed for `'a`
104 | eprintln!("{:#?}", err_lines.collect::<Vec<_>>());
105 | }
| - `search_term` dropped here while still borrowed
Thank you! This was the example I was looking for. I thought it would instantly click when I saw this… but now I’m confused why this function compiles?
fn foo1() {
let lines = vec![
"info: whatever whatever",
"debug: nobody cares",
"error: everything sucks",
];
{
let err_search = ERR_SEARCH.to_owned();
let search_term = &err_search;
{
let err_lines = filter_strs(lines, search_term);
eprintln!("{:#?}", err_lines.collect::<Vec<_>>());
}
println!("{search_term}");
}
}
This seems like the same thing to me. Why does it fail when there is a function boundary in between?
It's because the compiler is able to coerce your Vec<&'static str> into a Vec<&'b str> by making the lifetime shorter so that the lifetime fits. (Here you may think of 'b as the scope of search_term.)
With impl IntoIterator, the compiler is not able to shorten the lifetime inside the iterator because the underlying type may be one where that isn't possible. That is, the lifetime is invariant.