Help returning reference to item pushed to vector

I get the following error and I'm not sure how to fix it:

error[E0515]: cannot return value referencing temporary value
  --> src/core/entity.rs:28:9
   |
28 |         self.entities.borrow().last().unwrap()
   |         ----------------------^^^^^^^^^^^^^^^^
   |         |
   |         returns a value referencing data owned by the current function
   |         temporary value created here

I'm trying to create an Entity struct, store it in a vector inside an EntityManager and then return a reference to the Entity. The vector is contained within a RefCell because I want the EntityManager to be immutable, hence the interior mutability. I can't return an owned value because I move it when pushing onto the vector.

struct Entity {
    id: u32
}

struct EntityManager {
    next_id: Cell<u32>,
    entities: RefCell<Vec<Entity>>
}

impl EntityManager {
    pub fn new() -> EntityManager {
        EntityManager {
            next_id: Cell::new(0),
            entities: RefCell::new(vec![])
        }
    }

    pub fn create_entity(&self) -> &Entity {
        let id = self.next_id.get();
        let entity = Entity { id };
        self.next_id.set(id + 1);
        self.entities.borrow_mut().push(entity);
        self.entities.borrow().last().unwrap()
    }
}

Please could someone help me understand how to solve this?

When you are calling borrow, you are creating new object of type Ref<T> (T in this case is Vec<Entity>), which ensures, that while you have borrowed RefCell (your entity here), there is nothing borrowing it mutably in the same time. Everything you are later getting operating on this borrow, it is bound to the Ref object, not to entity (or self), so you cannot return reference to Entity in this function - it is because the borrows becomes invalid, when Ref goes out of scope which is in the end of create_entity function.

What you can do is to return Ref<Entity> taking advantage, that Ref is actually a monad - you may easly map internall value it holds. It should look like this:

    pub fn create_entity(&self) -> Ref<Entity> {
        let id = self.next_id.get();
        let entity = Entity { id };
        self.next_id.set(id + 1);
        self.entities.borrow_mut().push(entity);
        let ent = self.entities.borrow();
        Ref::map(ent, |entities| entities.last().unwrap())
    }
1 Like

Why returning a reference at all? Returning the struct by value seems a better idea.

How would that work, given it is moved when pushing to the vector?

As long, as entity is really small, you may just clone it before pushing to vector, or even you may make it Copy.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.