How to reference the item of a vector

Hi!
So, for learning purposes I'm trying to model a "maze" structure. A Maze is a collection of Rooms. Each Room object has an unique id and an array of adjacent rooms.

I've defined the Maze as having a vector or Reference Counted RefCells of Rooms, so that each room can be shared and modified.

The room has an array of 4 Optional neighbour-rooms, each being a reference to one of the other Rooms stored in the Maze vector.

You can see it in action here

I'm aware that this could be simplified by simply storing for each room an array of ids, but again, I'm studying Rust and I want a better understanding of references, lifetimes, borrowing.

The problem arises in the constructor the Maze struct where I loop each room and apply some logic (skipped in the pasted example as it doesn't really add anything to the problem) to find suitable neighbours and fill the room's neighbour array accordingly.

The code doesn't work. The first problem is that within the constructor function iterating the rooms object takes ownership of it and so I cannot associate it to the .rooms property of the Maze I am initializing.

The second problem is that looking for a room actually takes ownership of it and I don't know how to express "ok, this room is suitable as a neighbour, now only give me a reference to it and forget about about the actual room altogether".

Any help on how to overcome these two errors? Also, does my use of Rc, RefCell, Option, references make sense? Thanks!

If you have a variable room of the type Rc<RefCell<Room>>, you can create another reference counted reference by using Rc::clone(&room). You have ownership of each reference-counted handle to the room, not to the room itself.

If you have a room that isn't wrapped in an Rc, you would have to put it in an Rc.

One thing you have to watch out for is that this approach very easily results in memory leaks. One way to combat this would be to destroy all cycles using something like this:

impl Drop for Maze {
    fn drop(&mut self) {
        for room in &self.rooms {
            room.up = None;
            room.down = None;
            room.left = None;
            room.right = None;
        }
    }
}

Hi Alice, and thanks for your time. If I've understood your suggestion correctly, cloning the reference still doesn't make the code compile. Here it is the updated version

The Rc is a replacement for &'a, so you shouldn't use both: playground.

1 Like

Oh, gotcha! Thanks :slight_smile:

Also, instead of using Drop to clear the neighbors, you can use Weak to store the neighbors to avoid leaks.

Having a Weak there could carry the semantic of a room may no longer exist while still (weakly) referencing it.