How can I collapse using a HashMap as an accumulator?

This code works:

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

      

This code crashes with the message: "cannot exit acc

because it is borrowed"

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

      

+3


source to share


1 answer


You cannot return acc

from a closure because you have a mutable borrow for it that still exists ( counter

).

You can introduce a new scope to limit volatile borrowing:

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

      

Or you can remove the borrowing entirely by reducing it to one line:

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

      



I assumed that Rust would know it would counter

go out of scope after being returnedacc

This is understandable, but Rust simply aligns with how links work when the referenced item moves. In this case, you move the battery to the "output slot". You can also see this with simple functions:

fn foo(mut s: Vec<u8>) -> Vec<u8> {
    let borrow = &mut s[0];
    s
}

fn main() {}

      

But this is actually the same as moving the specified variable:

fn main() {
    let mut s = Vec::<u8>::new();
    let borrow = &mut s[0];
    let s2 = s;
}

      

+9


source







All Articles