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:
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.