Description
Edit: there is a simpler example I found below in the comments
I was trying to solve a lifetime issue another Rustacean had on the Reddit question thread and found this:
use std::collections::HashMap;
use std::thread;
fn get_chunks(string: &str, num: usize) -> Vec<&str> {Vec::new()}
pub fn count_words(string: &str)
-> HashMap<&str,usize> {HashMap::new()}
pub fn count_words_parallel(string: &str, threads: usize)
-> HashMap<&str,usize> {
let result = HashMap::new();
let chunks = get_chunks(string.clone(), threads);
let mut handles = Vec::with_capacity(chunks.len());
for chunk in chunks {
handles.push(thread::spawn(|| {
count_words(&chunk)
}));
}
for handle in handles {
if let Ok(counts) = handle.join() {
for (word, count) in counts {
match result.get(word) {
Some(original) => result.insert(word, original + count),
None => result.insert(word, count)
};
}
}
}
return result;
}
which triggers this gem (on rustc 1.44.0-nightly (6dee5f112 2020-04-06)
):
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src\main.rs:12:36
|
12 | let chunks = get_chunks(string.clone(), threads);
| ^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the function body at 9:1...
--> src\main.rs:9:1
|
9 | / pub fn count_words_parallel(string: &str, threads: usize)
10 | | -> HashMap<&str,usize> {
11 | | let result = HashMap::new();
12 | | let chunks = get_chunks(string.clone(), threads);
... |
32 | | return result;
33 | | }
| |_^
note: ...so that the types are compatible
--> src\main.rs:12:36
|
12 | let chunks = get_chunks(string.clone(), threads);
| ^^^^^
= note: expected `&&str`
found `&&str`
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `std::collections::HashMap<&str, usize>` will meet its required lifetime bounds
--> src\main.rs:16:22
|
16 | handles.push(thread::spawn(|| {
| ^^^^^^^^^^^^^
error: aborting due to previous error
besides the title, there are other problems with the error reporting that happens with and without that clone
:
Just to make sure I am interpreting the problem as a whole right, is the lifetime of the &str
passed to count_words_parallel
getting elided along until it gets into the new threads via &chunk
? The lifetimes of the new threads are 'static
which means that lifetime all the way back at the &str
must also be 'static
or alternatively something has to happen along the way to split up lifetimes (which I was trying to do above via clone
ing).
The important point is that I had to work through all the lifetimes myself by prompting the compiler through other errors (in which it will give more info) to figure out what was what. Hindsight of course is 20/20 and now I can see the flow of this particular error message, this is what I think it is trying to tell me:
note: first, the lifetime cannot outlive the anonymous lifetime
"the lifetime" refers to the hashmap at the end of the lifetime elision chain mentioned at the end of the error.
but, the lifetime must be valid for the static lifetime
I actually don't know what the first "lifetime" is but the "static lifetime" must be the thread spawning closure which is never pointed to (via the really helpful ascii lines and arrows).
so that the type std::collections::HashMap<&str, usize> will meet its required lifetime bounds
"required" as in required by the lifetime of the thread spawning closure that was indirectly mentioned above this part of the error. "bounds" as in 'static
The biggest problem I have always had with Rustc's error system when I get stuck is that a key piece of information is being withheld from me, and I believe it would help at this point to be more verbose and have redundancy to the wording. Perhaps have an error format that, for each lifetime involved, describes the where and what of the relevant variables and their lifetimes (saying stuff like "variable x has lifetime # 3, beginning and ending here"), and only after that describes what and how lifetimes collide (saying stuff like "this variable (having lifetime # 3) outlives this other variable (having lifetime # 2) via scoping or closures or whatnot at this place").