该代码适用于:

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,因为它是borrow 的"

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
    });

推荐答案

你不能从闭包中返回acc,因为你有一个仍然存在的可变借来(counter).

这是Rust编译器(尤其是borrow checker)的一个限制.启用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之前,编译器对于borrow 的持续时间过于保守.为了解决这个问题,您可以引入一个新范围来约束可变borrow :

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);
}

您还可以防止borrow 超出所需的期限:

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知道,一旦acc被退回,counter就会超出范围

这是可以理解的,并且与非词汇生命周期的讨论有关."好"消息是,当被引用的对象移动时,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之前都会失败,在NLL之后也会起作用.

Rust相关问答推荐

为什么这些From A和From B植入会导致重复的实现错误?

在‘await’点上使用‘std::同步::Mutex’是否总是会导致僵局?

Rust kill std::processs::child

下载压缩文件

有没有更好的方法从HashMap的条目初始化 struct ?

带扫描的铁 rust 使用滤镜

自定义结果枚举如何支持`?`/`FromResidual`?

如何在Rust中基于字符串 Select struct ?

你能在Rust中弃用一个属性吗?

为什么特征默认没有调整大小?

str 和 String 的 Rust 生命周期

如何递归传递闭包作为参数?

内部值发生变化时 Rc 的行为

类型判断模式匹配panic

将一片字节复制到一个大小不匹配的数组中

`map` 调用在这里有什么用吗?

如何在 Rust 中编写涉及异步的重试函数

意外的正则表达式模式匹配

如何在 C++ 和 Rust 之间共享 pthread 同步原语?

当 `T` 没有实现 `Debug` 时替代 `unwrap()`