为什么 csv::Reader 的记录中的字符串在插入到 HashMap 中后存活时间不够长?
Why do strings from a csv::Reader's records not live long enough when inserted into a HashMap?
我对 Rust 的整个生命周期概念还很陌生。我正在尝试从 CSV 文件中读取一些数据并将它们放入 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);
}
}
}
但是出现以下错误:
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
我认为插入 HashMap
会转移所有权,因此记录在循环外也可用。我在这里做错了什么?
看这段代码:
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);
}
}
它创建了一个包含对某些字符串的引用的 HashMap
,但这些字符串的所有者是什么?是rr
;因此你的错误信息。
代码如下:
Reader::from_path
从磁盘读取 CSV,rdr
拥有该结果。
Reader::records
的文档说(强调我的):
Returns a borrowed iterator over all records as strings.
因此迭代器不能超过 Reader
.
StringRecord::get
的API是:
pub fn get(&self, i: usize) -> Option<&str>
这个 returns 一个字符串引用,只要 self
有效。
通过跟踪这一点,您尝试插入的字符串切片实际上引用了 StringRecord
拥有的数据。这些记录在 for
循环体的末尾被丢弃,如错误消息中所示。允许您在循环后拥有这些引用会导致内存不安全,因此编译器会阻止您。
改为插入 String
s 允许代码继续:
topics.insert((filename, value1.to_owned()), value2.to_owned());
I thought insertion into the HashMap
transfers ownership
是的,确实如此。参考文献 的所有权 已转让。这些参考文献所指的不是。
另请参阅:
问题在于 CSV 字段仅在 CSV 行存在时存在,而您正试图将字段的借用保存到比 CSV 存在时间更长的主题中 reader。
为此,您需要 HashMap
通过将字段复制或移动到哈希图中来取得 CSV 字段的所有权。为此,您需要在地图中使用 String
s 而不是 &str
s。
这会做你想做的事:
extern crate csv;
use std::collections::HashMap;
fn main() {
let files = vec!["file1.csv", "file2.csv", "file3.csv"];
let mut topics: HashMap<(String, String), String> = 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.into(), value1.into()), value2.into());
}
}
}
我对 Rust 的整个生命周期概念还很陌生。我正在尝试从 CSV 文件中读取一些数据并将它们放入 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);
}
}
}
但是出现以下错误:
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
我认为插入 HashMap
会转移所有权,因此记录在循环外也可用。我在这里做错了什么?
看这段代码:
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);
}
}
它创建了一个包含对某些字符串的引用的 HashMap
,但这些字符串的所有者是什么?是rr
;因此你的错误信息。
代码如下:
Reader::from_path
从磁盘读取 CSV,rdr
拥有该结果。Reader::records
的文档说(强调我的):Returns a borrowed iterator over all records as strings.
因此迭代器不能超过
Reader
.StringRecord::get
的API是:pub fn get(&self, i: usize) -> Option<&str>
这个 returns 一个字符串引用,只要
self
有效。
通过跟踪这一点,您尝试插入的字符串切片实际上引用了 StringRecord
拥有的数据。这些记录在 for
循环体的末尾被丢弃,如错误消息中所示。允许您在循环后拥有这些引用会导致内存不安全,因此编译器会阻止您。
改为插入 String
s 允许代码继续:
topics.insert((filename, value1.to_owned()), value2.to_owned());
I thought insertion into the
HashMap
transfers ownership
是的,确实如此。参考文献 的所有权 已转让。这些参考文献所指的不是。
另请参阅:
问题在于 CSV 字段仅在 CSV 行存在时存在,而您正试图将字段的借用保存到比 CSV 存在时间更长的主题中 reader。
为此,您需要 HashMap
通过将字段复制或移动到哈希图中来取得 CSV 字段的所有权。为此,您需要在地图中使用 String
s 而不是 &str
s。
这会做你想做的事:
extern crate csv;
use std::collections::HashMap;
fn main() {
let files = vec!["file1.csv", "file2.csv", "file3.csv"];
let mut topics: HashMap<(String, String), String> = 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.into(), value1.into()), value2.into());
}
}
}