I am counting the number of times a word appears in Macbeth:
use std::io::{BufRead, BufReader};
use std::fs::File;
use std::collections::HashMap;
fn main()
The error is both right and wrong here. l
is blamed, because w
lives only as long as l
(and l.unwrap()
) and l
doesn't live long enough to put it in hashmap in a higher scope.
In practice, you just have to look at what other variables depend on the lifetime of a variable the compiler complains about.
But Rust is also working lately on improving error reporting, so I'd raise this case as potential bug.
is pointing the blame at
l
It's not, really. Review the error message again:
for w in l.unwrap().split_whitespace() {
---------- temporary value created here
The error marker is pointing to the call of unwrap
on l
.
when the issue is
w
It's not, really. l
is of type Result<String>
. When you call unwrap
, you get a String
, and then split_whitespace
returns references to that string. These references live only as long as the string, but your code tries to put them into a hashmap that will live longer than the string. The problem is that the l.unwrap()
doesn't live long enough, and w
is just a reference to the thing that doesn't live long enough.
Conceptually, it's the same problem as this code:
use std::collections::HashMap;
fn main() {
let mut counts = HashMap::new();
{
let s = String::from("hello world");
counts.insert(&s, 0);
}
println!("{:?}", counts);
}
Which also points to s
and says it doesn't live long enough (because it doesn't).
The correct solution is to convert each word into an owned String
which the HashMap
can then hold:
for l in reader.lines() {
for w in l.unwrap().split_whitespace() {
counts.entry(w.to_string()).or_insert(0) += 1;
}
}