I'm new to the whole lifetime concept of Rust. I'm trying to read some data from CSV files and put them into a HashMap
:
extern crate csv;
use std::collections::HashMap;
fn main() {
let files = vec!["file1.csv", "file2.csv", "file3.csv"];
let mut topics: HashMap<(&str, &str), &str> = HashMap::new();
for filename in files {
let mut rdr = csv::Reader::from_path(filename).unwrap();
for rec in rdr.records() {
let rr = rec.unwrap();
let value1 = rr.get(0).unwrap();
let value2 = rr.get(1).unwrap();
topics.insert((filename, value1), value2);
}
}
}
However the following error occurs:
error[E0597]: `rr` does not live long enough
--> src/main.rs:14:26
|
14 | let value1 = rr.get(0).unwrap();
| ^^ borrowed value does not live long enough
...
17 | }
| - `rr` dropped here while still borrowed
18 | }
19 | }
| - borrowed value needs to live until here
I thought insertion into the HashMap
transfers ownership and thus the records are available also outside of the loop. What am I doing wrong here?
Look at this piece of code:
let mut topics: HashMap<(&str, &str), &str> = HashMap::new();
for filename in files {
let mut rdr = csv::Reader::from_path(filename).unwrap();
for rec in rdr.records() {
let rr = rec.unwrap();
let value1 = rr.get(0).unwrap();
let value2 = rr.get(1).unwrap();
topics.insert((filename, value1), value2);
}
}
It creates a HashMap
that contains references to some strings, but what is the owner of those strings? It is rr
; thus your error message.
Following the code:
Reader::from_path
reads the CSV from disk and rdr
owns that result.
The documentation for Reader::records
says (emphasis mine):
Returns a borrowed iterator over all records as strings.
Thus the iterator cannot outlive the Reader
.
StringRecord::get
's API is:
pub fn get(&self, i: usize) -> Option<&str>
This returns a string reference that only lives as long as self
does.
By tracing this, the string slices you are attempting to insert actually reference data owned by the StringRecord
. These records are dropped at the end of the for
loop's body, as shown in the error message. It would cause memory unsafety to allow you to have these references after the loop, thus the compiler stops you.
Inserting String
s instead allows the code to continue:
topics.insert((filename, value1.to_owned()), value2.to_owned());
I thought insertion into the
HashMap
transfers ownership
Yes, it does. The ownership of the references is transferred. The thing those references refer to is not.
See also: