Borrow checker: create iterator in one method and iterate in another

I'm trying to create a ReadDir iterator in a method and store it in a HashMap. Another method will then use this iterator.

The code below currently does not compile. I've tried a few things and I understand why they don't work, but I'm unsure how I can keep the borrow checker happy in this case.

By storing a ReadDir in the map I can't iterate in iterate() because it would need ownership of the iterator. So it would seem logical that I would need to store a &mut. But by doing that in create() fs::read_dir() will "create a temporary value which is freed while still in use".

How would you suggest I create the iterator in one method and iterate over it in the other?

Note: I could collect the interator into a Vec in create() but I do not intend to do that, I want to keep the iterator.

use std::collections::HashMap;
use std::fs::{self, ReadDir};

struct Test {
    test: HashMap<i64, ReadDir>,
}

impl Test {
    fn create(&mut self) {
        self.test.insert(0, fs::read_dir(".").unwrap());
    }

    fn iterate(&self) {
        let &mut r = self.test.get(&0).unwrap();
        // let mut r = fs::read_dir(".").unwrap();
        let d = r.next();
        println!("{:?}", d);
    }
}

fn main() {
    let mut c = Test {test: HashMap::new()};

    c.create();
    c.iterate();
}

Compilation output:

error[E0308]: mismatched types
  --> src/main.rs:14:13
   |
14 |         let &mut r = self.test.get(&0).unwrap();
   |             ^^^^^^   -------------------------- this expression has type `&ReadDir`
   |             |
   |             types differ in mutability
   |             help: to declare a mutable variable use: `mut r`
   |
   = note:      expected reference `&ReadDir`
           found mutable reference `&mut _`

For more information about this error, try `rustc --explain E0308`.
error: could not compile `test21` due to previous error

Try using HashMap::get_mut:

use std::collections::HashMap;
use std::fs::{self, ReadDir};

struct Test {
    test: HashMap<i64, ReadDir>,
}

impl Test {
    fn create(&mut self) {
        self.test.insert(0, fs::read_dir(".").unwrap());
    }

-    fn iterate(&self) {
-       let &mut r = self.test.get(&0).unwrap();   
+    fn iterate(&mut self) {
+       let r = self.test.get_mut(&0).unwrap();
        let d = r.next();
        println!("{:?}", d);
    }
}

fn main() {
    let mut c = Test {test: HashMap::new()};

    c.create();
    c.iterate();
}

Playground.

2 Likes

It was that simple... Thank you very much! Clearly I need to study the docs for HashMap.

That wasn't really a problem. let &mut var = value; pattern matches on the value, and provided that it was a mutable reference, it removes a layer of mutable reference, ie. dereferences it. It doesn't create a mutable reference.

You are probably confusing patterns with expressions.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.