rust - Why do I have to use &char instead of char to index a key in a HashMap<char, i32>? - Stack Overflow

时间: 2025-01-06 admin 业界

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 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.

Share Improve this question edited 14 hours ago John Kugelman 361k69 gold badges546 silver badges591 bronze badges asked 15 hours ago Eason ZhangEason Zhang 111 silver badge1 bronze badge New contributor Eason Zhang is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
Add a comment  | 

1 Answer 1

Reset to default 3

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.

  • Which means when K is char, Q is also char
  • Which means Index<&Q> is Index<&char>
  • Which means you can use &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.