4

In order to test the Index trait, I coded a histogram.

use std::collections::HashMap;

fn main() {
    let mut histogram: HashMap<char, u32> = HashMap::new();
    let chars: Vec<_> = "Lorem ipsum dolor sit amet"
        .to_lowercase()
        .chars()
        .collect();

    for c in chars {
        histogram[c] += 1;
    }

    println!("{:?}", histogram);
}

Test code here.

But I get following type error expected &char, found char. If I use histogram[&c] += 1; instead, I get cannot borrow as mutable.

What am I doing wrong? How can I fix this example?

mike
  • 4,929
  • 4
  • 40
  • 80

1 Answers1

5

HashMap only implements Index (and not IndexMut):

fn index(&self, index: &Q) -> &V

so you can't mutate histogram[&c], because the returned reference &V is immutable.

You should use the entry API instead:

for c in chars {
    let counter = histogram.entry(c).or_insert(0);
    *counter += 1;
}
ljedrz
  • 20,316
  • 4
  • 69
  • 97
  • So what can I do, if I want to update my histogram with the bracket operator? Is it possible to implement `IndexMut` for `HashMap`? – mike Jun 02 '17 at 10:51
  • 2
    [Entry API](https://doc.rust-lang.org/std/collections/struct.HashMap.html#method.entry) provides a way to do it. The example solves your problem. – red75prime Jun 02 '17 at 10:53
  • @mike you can't implement `IndexMut` for `HashMap`, because only traits defined in the current crate can be implemented for a type parameter ([E0210](https://doc.rust-lang.org/error-index.html#E0210)). I think it was not implemented in the std in favor of the entry API. – ljedrz Jun 02 '17 at 11:01
  • It was removed "[...] in order to future-proof the API against the eventual inclusion of an `IndexSet` trait." https://github.com/rust-lang/rust/pull/23559 ...Why!? This succinct updating of maps like C++ is so beautiful! – mike Jun 02 '17 at 11:05