Rewrite string group-by code as idiomatic rust


#1

I have this code that does a group-by on the characters of a string. It feels very hacky with the declaration of zero as a variable, and also feels somewhat verbose having to put the computation for current_count on a separate line. Can anyone help me turn this code into idiomatic Rust please?

use std::collections::HashMap;

fn main() {
    let some_string = "haha";
    let mut stats: HashMap<char, u64> = HashMap::new();
    for char in some_string.chars() {
        // &0 doesn't work but &zero does, and a reference is needed, so define zero
        let zero = 0;
        // cannot use stats.get in same line as stats.insert because I'm borrowing
        // one as immutable and the other as mutable
        let current_count = *stats.get(&char).unwrap_or(&zero);
        // finally update the hashmap
        stats.insert(char, current_count + 1);
    }
    println!("{:?}", stats); // {'a': 2, 'h': 2}
}

#2

use entry():

use std::collections::HashMap;

fn main() {
    let some_string = "haha";
    let mut stats: HashMap<char, u64> = HashMap::new();
    for ch in some_string.chars() {
        *stats.entry(ch).or_insert(0) += 1;
    }
    println!("{:?}", stats); // {'a': 2, 'h': 2}
}

#3

Also, &0 works for me. Alternatively, you can use .cloned():

use std::collections::HashMap;

fn main() {
    let some_string = "haha";
    let mut stats: HashMap<char, u64> = HashMap::new();
    for char in some_string.chars() {
        let current_count = stats.get(&char).cloned().unwrap_or(0);
        // finally update the hashmap
        stats.insert(char, current_count + 1);
    }
    println!("{:?}", stats); // {'a': 2, 'h': 2}
}

Regardless, do what @birkenfeld said.