Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Can you explain why this solution to rust's borrow checker error?

This might not be the right place to ask this, but I’m working on interview questions in Rust. The problem is to define an in-memory FileSystem and I’m using a recursive FileSystem type plus Node enum.

enum Node {
  File(String),
  Directory(FileSystem)
}
struct FileSystem {
  storage: HashMap<String,Box<Node>>
}

Here was my first attempt at implementing mkdir,

impl FileSystem {
...
 
    fn mkdir(&mut self, path: String) {
      let directories = path.split("/").map(|s| s.to_owned()).collect::<Vec<_>>();
      let mut curr = self;
      for dir in &directories {
        if !curr.storage.contains_key(dir) {
          let filesystem = FileSystem::new();
          let new_node = Box::new(Node::Directory(filesystem));
          curr.storage.insert(dir.to_string(), new_node);
        }
        if let Some(&mut f) = curr.storage.get_mut(dir) {
          match *f {
            Node::Directory(d) => *curr = d,
            _ => unreachable!()
          }
        }
      }
    }
...
}

Which gives the following error:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Line 62, Char 31: cannot move out of a mutable reference (solution.rs)
   |
62 |         if let Some(&mut f) = curr.storage.get_mut(dir) {
   |                          -    ^^^^^^^^^^^^^^^^^^^^^^^^^
   |                          |
   |                          data moved here
   |                          move occurs because `f` has type `Box<Node>`, which does not implement the `Copy` trait
Line 74, Char 13: borrow of moved value: `self` (solution.rs)

and chatgpt gave me the following solution that compiles, but I’m having trouble grokking the underlying reason that tossing the Box inside a closure fixes the borrow checker error.

impl FileSystem {
...
fn mkdir(&mut self, path: String) {
      let directories = path.split("/").map(|s| s.to_owned()).collect::<Vec<_>>();
      let mut curr = &mut self.storage;
      for dir in directories {
        let next = curr.entry(dir).or_insert_with(|| Box::new(Node::Directory(FileSystem::new())));
        match next.as_mut() {
          Node::Directory(d) => curr = &mut d.storage,
          _ => unreachable!()
        }
      }
    }
...
}

>Solution :

&mut in pattern position will dereference the value.

HashMap::get_mut already returns an Option<&mut T> Some(f) would have created an f of type &mut T which is what you wanted. There are exceptions but generally the pattern does the reverse of the value literal so:

  value: Some(&mut T)
pattern: Some(&mut f)

thus f: T, and rust has to dereference and try to move the value for that to work, which it doesn’t because Node is not Copy.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading