In the following snippet, given the type of 'a'
is char
, why can't I print letters['a']
?
use std::collections::HashMap;
fn main() {
let mut letters = HashMap::new();
for ch in "a short treatise on fungi".chars() {
letters.entry(ch).and_modify(|counter| *counter += 1).or_insert(1);
}
println!("{}", letters[&'a']);
}
I have tried to print the type of letters
, which is std::collections::hash::map::HashMap<char, i32>
, the type of 'a'
, which is char
, and the type of &'a'
, which is &char
.
In Rust, the subscript operator []
is implemented using the Index
trait. Index
is generic over the type doing the indexing, so impl Index<usize> for Type
means any Type
value can be indexed with any usize
value.
The impl for HashMap
looks like this:
impl<K, Q, V, S> Index<&Q> for HashMap<K, V, S>
where
K: Eq + Hash + Borrow<Q>,
Q: Eq + Hash + ?Sized,
S: BuildHasher,
K
is the key type in the HashMap
, and the indexing type is &Q
. These are linked by K: Borrow<Q>
. We know K
is char
, so for which Q
does K
implement Borrow<Q>
?
impl<T> Borrow<T> for T
where
T: ?Sized,
Here, T
is char
, so the only implementation is impl Borrow<char> for char
.
K
is char
, Q
is also char
Index<&Q>
is Index<&char>
&char
to index HashMap<char, _>
This is done because we want an extensible way to index, for example, HashMap<String, _>
with &str
, since String
may be expensive to create. But unfortunately, this means we can't also have impl Index<K> for HashMap<K, _>
. So we're stuck borrowing every index, whether it makes sense or not.