此代码有效:
let stdin = std::io::stdin();
let mut rdr = csv::Reader::from_reader(stdin);
let mut hmap = HashMap::<String, u64>::new();
rdr.records()
.map(|r| r.unwrap())
.fold((), |_, item| {
// TODO: Is there a way not to have to copy item[col] every time?
let counter = hmap.entry(item[col].to_string()).or_insert(0);
*counter += 1;
});
此代码失败并显示以下消息:“无法移出acc
,因为它是借用的”
let stdin = std::io::stdin();
let mut rdr = csv::Reader::from_reader(stdin);
let hmap = rdr.records()
.map(|r| r.unwrap())
.fold(HashMap::<String, u64>::new(), |mut acc, item| {
// TODO: Is there a way not to have to copy item[col] every time?
let counter = acc.entry(item[col].to_string()).or_insert(0);
*counter += 1;
acc
});
答案 0 :(得分:14)
你不能从闭包中返回acc
,因为你有一个仍然存在的可变借位(counter
)。
这是Rust编译器的限制(特别是借用检查器)。启用non-lexical lifetimes后,原始代码将起作用:
#![feature(nll)]
use std::collections::HashMap;
fn main() {
let hmap = vec![1, 2, 3].iter().fold(HashMap::new(), |mut acc, _| {
let counter = acc.entry("foo".to_string()).or_insert(0);
*counter += 1;
acc
});
println!("{:?}", hmap);
}
在NLL之前,编译器对借用持续多长时间过于保守。要解决这个问题,您可以引入一个新范围来约束可变借用:
use std::collections::HashMap;
fn main() {
let hmap = vec![1, 2, 3].iter().fold(HashMap::new(), |mut acc, _| {
{
let counter = acc.entry("foo".to_string()).or_insert(0);
*counter += 1;
}
acc
});
println!("{:?}", hmap);
}
您还可以阻止借款超出其所需的界限:
use std::collections::HashMap;
fn main() {
let hmap = vec![1, 2, 3].iter().fold(HashMap::new(), |mut acc, _| {
*acc.entry("foo".to_string()).or_insert(0) += 1;
acc
});
println!("{:?}", hmap);
}
我认为Rust会在
counter
返回后知道acc
会超出范围
这是可以理解的,并且涉及非词汇生命期讨论。 “好”的消息是Rust在被引用的东西移动时,引用如何工作是一致的。在这种情况下,您将累加器移动到“输出槽”。您也可以通过普通函数看到这一点:
fn foo(mut s: Vec<u8>) -> Vec<u8> {
let borrow = &mut s[0];
s
}
fn main() {}
但实际上,它与移动引用变量完全相同:
fn main() {
let mut s = Vec::<u8>::new();
let borrow = &mut s[0];
let s2 = s;
}
这两个都在NLL之前失败并且之后继续工作。