如何使用HashMap折叠作为累加器?

克里斯托弗·戴维斯(Christopher Davies)

此代码有效:

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
    });
谢泼玛特

您无法acc从闭包中返回,因为您有对它的可变借用,而该借用仍然存在(counter)。

这是Rust编译器(特别是借用检查器)的限制。非词汇的寿命被启用,原来的代码将工作:

#![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之前都失败了,然后才起作用。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

使用数组作为Scala foldLeft累加器

来自分类Dev

使用对象作为累加器的数组减少

来自分类Dev

如何使用OpenCL内核来做累加器?

来自分类Dev

如何实现timespec累加器?

来自分类Dev

使用HashBasedTable作为累加器的Guava ImmutableTable的Java 8收集器给出了IllegalAccessError

来自分类Dev

在分机上使用累加器

来自分类Dev

使用累加器的树的大小

来自分类Dev

使用累加器的树的大小

来自分类Dev

如何使用 chrono 为带有累加器定时器的算法计时?

来自分类Dev

如何在Rx.Net中使用异步累加器实现ScanAsync运算符?

来自分类Dev

如何使用组和累加器阶段改善MongoDB聚合?

来自分类Dev

如何将 ImmutableJS 的 reduce 函数与不可变累加器一起使用?

来自分类Dev

如何将Spark的累加器传递给函数?

来自分类Dev

reduce()的累加器和当前参数应如何键入?

来自分类Dev

如何正确处理Python时钟中的累加器?

来自分类Dev

pyspark矩阵累加器

来自分类Dev

列表累加器在Erlang

来自分类Dev

列表累加器在Erlang

来自分类Dev

Erlang导致累加器

来自分类Dev

使用Clojure中的累加器进行映射?

来自分类Dev

Data.Vector,使用累加器进行映射

来自分类Dev

使用累加器遍历Node.js异步目录

来自分类Dev

F#–使用累加器映射列表

来自分类Dev

Prolog使用累加器在列表中查找元素

来自分类Dev

使用数组reduce typescript将类型赋予累加器

来自分类Dev

Haskell使用累加器与Parsec进行解析

来自分类Dev

使用累加器连接数字列表

来自分类Dev

使用Clojure中的累加器进行映射?

来自分类Dev

使用累加器遍历Node.js异步目录