Iterate through a generic hashmap


#1

Here is the code:

use std::collections::HashMap;

fn print_map<K, V>(map: &HashMap<K, V>) {
    for (k, v) in map {
        println!("{:?}: {:?}", k, v);
    }
}

fn main() {
    let mut map = HashMap::new();
    map.insert("blue".to_string(), 10);
    map.insert("yellow".to_string(), 50);
    {
        let score = map.get("blue");
    }
    print_map::<String, i32>(&map);
    map.insert(String::from("blue"), 11);
    print_map::<String, i32>(&map);
}

Result from build:

cargo build
   Compiling communicator v0.1.0 (file:///home/kaiyin/IdeaProjects/communicator)
error[E0277]: the trait bound `&std::collections::HashMap<K, V>: std::iter::IntoIterator` is not satisfied
 --> src/main.rs:4:5
  |
4 | /     for (k, v) in map {
5 | |         println!("{:?}: {:?}", k, v);
6 | |     }
  | |_____^ the trait `std::iter::IntoIterator` is not implemented for `&std::collections::HashMap<K, V>`

Then I changed the for loop a bit:

    for (k, v) in map.iter() { ...

And now I got this error:

   Compiling communicator v0.1.0 (file:///home/kaiyin/IdeaProjects/communicator)
error[E0599]: no method named `iter` found for type `&std::collections::HashMap<K, V>` in the current scope
 --> src/main.rs:4:23
  |
4 |     for (k, v) in map.iter() {
  |                       ^^^^
  |
  = note: the method `iter` exists but the following trait bounds were not satisfied:
          `K : std::cmp::Eq`
          `K : std::hash::Hash`
          `K : std::cmp::Eq`
          `K : std::hash::Hash`

This is a bit confusing. String obviously should satisfy all these bounds, right?


#2

The bounds are checked locally, and you did not put them on K and V. This works: https://play.rust-lang.org/?gist=4f475377ad79e08197d2ba2f9b0666dd&version=undefined


#3

This works:

use std::collections::HashMap;
use std::fmt::Debug;
use std::hash::Hash;

fn print_map<K: Debug + Eq + Hash, V: Debug>(map: &HashMap<K, V>) {
    for (k, v) in map.iter() {
        println!("{:?}: {:?}", k, v);
    }
}

fn main() {
    let mut map = HashMap::new();

    map.insert("blue".to_string(), 10);
    map.insert("yellow".to_string(), 50);

    println!("{:?}", map.get("blue"));
    print_map(&map);
    map.insert(String::from("blue"), 11);
    print_map(&map);
}

String satisfies those traits, but unlike C++ a generic Rust function needs to compile for all the types it could be instantiated with.


#4

https://github.com/rust-lang/rfcs/blob/master/text/2089-implied-bounds.md might make this a bit easier in the future (although HashMap<K, V> doesn’t bound the types in its definition, only impl block).