Sheraff
Sheraff

Reputation: 6702

Ownership when each item in a vector needs all the other items in said vector

I'm very new to Rust and I'm having trouble figuring out how to handle ownership (and lifetime?) in this case. I'm not new to programming and I'm actually re-implementing something that already works in JS (https://sheraff.github.io/boids/).


In this context, Universe is basically a "simulation" environment containing many Entity. On each universe.tick(), each Entity needs to know which other Entity it can "see". For that, entity.update() takes a list of Entity as an argument.

As a result, I have this piece of script that I can't seem to find a good ownership structure for:

for mut entity in self.entities {
    entity.update(&self.entities);
}

How would you go about it?

I could tell you what I have tried but it feels like I have tried everything I could think of, including reading the Rust book, and I've had all the possible error messages... Sorry.


PS: of course, in time, it's not the entire list of entities that would be passed in entity.update but a filtered list.


Below is a general simplification of the code structure:

pub struct Entity {
    pub point: Point,
    vision: Cone,
    angle: Angle
}
impl Entity {
    pub fn update(&mut self, entities: &Vec<Entity>) {
        // ...
    }
}

pub struct Universe {
    pub entities: Vec<Entity>
}
impl Universe {
    pub fn new() -> Universe {
        let mut entities: Vec<Entity> = vec![];
        for _ in 1..200 {
            let mut entity = Entity::new();
            entities.push(entity);
        }

        Universe {
            entities
        }
    }

    pub fn tick(&self) {
        for mut entity in self.entities {
            entity.update(&self.entities);
        }
    }
}

Upvotes: 0

Views: 109

Answers (1)

Ted Klein Bergman
Ted Klein Bergman

Reputation: 9746

If each entity needs to know about each entity, then it seems like it's not the entity that's responsible for the update. You should probably refactor from a method on the entity to a function that operates on all entities.

Iterating over the entities in a nested loop is a bit difficult. One solution would be to iterate over one copy of the array and allow the other loop to take a mutable reference.

pub fn update_entities(entities: &mut Vec<Entity>) {
    for a in entities.clone() {
        for mut entity in entities.iter_mut() {
            if entity.id == a.id { // If you can compare them, otherwise use indexed for loop and compare indices.
                continue;
            }
            // Do stuff.
        }
    }
}

The reason why you need to copy is because of the golden rule of Rust: you can have either one mutable reference or any number of immutable references. Nested for loops break this rule because you need one mutable reference and one immutable.

Upvotes: 1

Related Questions