Why can't I use `into_iter()` but `drain()` in this code?

fn main() {
    let mut a:HashMap<String, Vec<i64>> = HashMap::from([(String::from("Sonic"), vec![1,2,3])]);
    
    for (k,v) in a.into_iter() {
        println!("{k:?}:{v:?}");
    }
    
    for i in 0..2 {
        a.entry(String::from("HOY")).or_insert(vec![]).push(i);
    }
    
    
    
}

This failed to compile.

error[E0382]: borrow of moved value: `a`
  --> src/main.rs:18:9
   |
9  |     let mut a:HashMap<String, Vec<i64>> = HashMap::from([(String::from("Sonic"), vec![1,2,3])]);
   |         ----- move occurs because `a` has type `HashMap<String, Vec<i64>>`, which does not implement the `Copy` trait
10 |     
11 |     for (k,v) in a.into_iter() {
   |                    ----------- `a` moved due to this method call
...
18 |         a.entry(String::from("HOY")).or_insert(vec![]).push(i);
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ value borrowed here after move
   |
note: `into_iter` takes ownership of the receiver `self`, which moves `a`
  --> /rustc/8ede3aae28fe6e4d52b38157d7bfe0d3bceef225/library/core/src/iter/traits/collect.rs:271:18
help: you can `clone` the value and consume it, but this might not be your desired behavior
   |
11 |     for (k,v) in a.clone().into_iter() {
   |                    ++++++++

For more information about this error, try `rustc --explain E0382`.

This was the error.

But when I switched .into_iter() into drain(), it worked.

Why does drain() work while not into_iter()?

The compiler already told you all there is to the error.

into_iter() takes the map by value, so it ceases to exist.

drain() simply mutates the map in place and removes all entries. The map will be empty but the variable will still be valid.

2 Likes