0

I have the following Rust structure which has a HashMap to children structures.

use std::collections::HashMap;

#[derive(Debug)]
struct Node {
    children: HashMap<i32, Node>,
}

impl Node {
    fn no_children(&self) -> usize {
        if self.children.is_empty() {
            1
        } else {
            1 + self
                .children
                .into_iter()
                .map(|(_, child)| child.no_children())
                .sum::<usize>()
        }
    }
}

I implemented no_children(&self) to find the total number of nodes. However, under self.children, Rust highlights an error because:

error[E0507]: cannot move out of `self.children` which is behind a shared reference
  --> src/lib.rs:13:17
   |
13 |               1 + self
   |  _________________^
14 | |                 .children
   | |_________________________^ move occurs because `self.children` has type `std::collections::HashMap<i32, Node>`, which does not implement the `Copy` trait

I am not sure what is missing. I have tried adding &self.children... but still got the same error.

Shepmaster
  • 274,917
  • 47
  • 731
  • 969
hydradon
  • 1,067
  • 10
  • 24

1 Answers1

2

The issue is that .into_iter(self) needs to take ownership of the HashMap, but in no_immediate_children(&self) the HashMap is behind a reference -> i.e. &self instead of self;

You can work around that in two ways, depending on what you want to achieve:

  1. If you want to consume the elements of the hash map and leave it empty after the method invocation:

    • Change the receiver to &mut self
    • Use .drain() instead of .into_iter():

      self.children.drain().map(|(_, mut v)| v.no_immediate_children()).sum::<usize>() + 1
      
  2. If you just want to get the sum, but do not want to modify the HashMap:

    • Use .iter() instead of .into_iter():

      self.children.iter().map(|(_k, v)| v.no_immediate_children()).sum::<usize>() + 1
      
  3. You want to consume the whole Node chain:

    • Change the method signature to fn no_immediate_children(self) and use .into_iter() as it is.
Shepmaster
  • 274,917
  • 47
  • 731
  • 969
Svetlin Zarev
  • 9,115
  • 3
  • 42
  • 69