J.F.
J.F.

Reputation: 63

"ambiguous associated type" error when pattern matching over a HashMap::Entry (Error code E0223)

I'm using a HashMap to store some important data, and I want to be able to look for a certain key, insert a value for it if it doesn't exist, and do stuff to the value if the key was found.

I stripped down the code to a minimal reproduction of the error, I'm not really trying to increment numbers. I do want to use the HashMap::Entry capabilities, iterating over all keys/values is not an alternative.

use std::collections::HashMap;

pub fn stack_overflow_example() -> bool {
    let hash_map: HashMap<i32, i32> = HashMap::new();
    let key = 1;

    match hash_map.entry(key) {
        HashMap::Entry::Vacant(entry) => entry.insert(vec![1]),
        HashMap::Entry::Occupied(entry) => {
            let mut numbers = entry.into_mut().iter_mut();
            let mut numbers_affected = 0;

            for number in numbers {
                if number < 10 {
                    number = number + 1;

                    numbers_affected += 1;
                }
            }

            if numbers_affected == 0 {
                numbers.push(1)
            }
        }
    }

    true
}

I get this error message:

error[E0223]: ambiguous associated type
 --> src/main.rs:8:9
  |
8 |         HashMap::Entry::Vacant(entry) => entry.insert(vec![1]),
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ambiguous associated type
  |
  = note: specify the type using the syntax `<std::collections::HashMap<_, _, _> as Trait>::Entry`

error[E0223]: ambiguous associated type
 --> src/main.rs:9:9
  |
9 |         HashMap::Entry::Occupied(entry) => {
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ambiguous associated type
  |
  = note: specify the type using the syntax `<std::collections::HashMap<_, _, _> as Trait>::Entry`

I tried doing what it says, but when I put those changes in, I can't put (entry) after Vacant and Occupied. Here is the error message:

error: unexpected `(` after qualified path
 --> src/main.rs:8:69
  |
8 |         <std::collections::HashMap<_, _, _> as Trait>::Entry::Vacant(entry) => entry.insert(vec![1]),
  |                                                                     ^

Should I really use 'Trait' literally? I don't know. Should I replace the underscores with the relevant types? Likely, yes, but I still get the same error.

Upvotes: 5

Views: 1180

Answers (1)

Shepmaster
Shepmaster

Reputation: 431689

There is a simple typo. Refer to the documentation for Entry:

std::collections::hash_map::Entry

You want to use something like

match hash_map.entry(key) {
    std::collections::hash_map::Entry::Vacant(entry) => (),
    std::collections::hash_map::Entry::Occupied(entry) => (),
}

Although it's normally

use std::collections::hash_map::Entry;

match hash_map.entry(key) {
    Entry::Vacant(entry) => (),
    Entry::Occupied(entry) => (),
}

This unlocks many other errors in the code:

  1. You cannot insert a vector because you've declared the hashmap as having a i32 as the value.
  2. There are mismatches with comparing references
  3. There are attempts to push a value onto an iterator.
  4. There is missing mutability.

Note that often you don't even need to match on Entry explicitly. Seems like the code should be

pub fn stack_overflow_example(hash_map: &mut HashMap<i32, Vec<i32>>) {
    let mut numbers_affected = 0;

    let numbers = hash_map.entry(1).or_insert_with(Vec::new);

    for number in numbers.iter_mut() {
        if *number < 10 {
            *number += 1;

            numbers_affected += 1;
        }
    }

    if numbers_affected == 0 {
        numbers.push(1)
    }
}

Upvotes: 4

Related Questions