ThePianoDentist
ThePianoDentist

Reputation: 73

How to take ownership of variable for non-function code-chunk

for tower in &mut game.towers {
    tower.towers_attack(&mut game)
};

gives cannot borrow game as mutable more than once at a time [E0499]

My code was working however I was refactoring for it to make more sense.

What did work was (main point to note is it is fine with looping twice mutably over the game object, however this is because function has ownership of 'game'?)

impl Attack for Game {
    fn towers_attack(&mut self) {
        for tower in &mut self.towers {
            tower.attacked = false;
            if tower.hp.is_positive() {
                for creep in &mut self.lane_creeps {
                    if tower.position.distance_between(creep.position) < 12.0 &&
                       creep.side != tower.side && !tower.attacked {
                        creep.hp -= tower.attack_damage as i32;
                        tower.attacked = true;
                        break;
                    }
                }
            }
        }
    }
}

game.towers_attack();

Moving the first loop to outside the function and implementing on tower rather than game.tower causes the issue.

I've confused myself a lot, I believe I just need to give ownership of game to for tower in &mut game.towers { tower.towers_attack(&mut game) }; then return ownership when it exits, therefore no borrowing occurs if I explicitly give ownership, however I'm not sure if this is possible or makes sense.

The towers_attack function is

impl TowerAttack for Tower {
    fn towers_attack(&mut self, game: &mut Game) {
        self.attacked = false;
        if self.hp.is_positive() {
            for creep in &mut game.lane_creeps {
                if self.position.distance_between(creep.position) < 12.0 &&
                   creep.side != self.side && !self.attacked {
                    creep.hp -= self.attack_damage as i32;
                    self.attacked = true;
                    break;
                }
            }
        }
    }
}

Upvotes: 2

Views: 106

Answers (1)

Shepmaster
Shepmaster

Reputation: 430721

for tower in &mut game.towers {
    tower.towers_attack(&mut game)
}

Rust prevents this call because the implementation of towers_attack might be:

fn towers_attack(game: &mut Game) {
    game.towers.clear()
}

or maybe

fn towers_attack(game: &mut Game) {
    game.towers.push(...)
}

which causes the vector to be reallocated and thus the iterator to be invalidated, which would cause Bad Things To Happen.

Instead, pass the subset of items you need to towers_attack. For example:

fn towers_attack(lane_creeps: &mut Vec<Creeps>) { ... }

I just need to give ownership of game to for tower in &mut game.towers { tower.towers_attack(&mut game) };

You always transfer ownership of the expression to the for loop. In this case, you are passing ownership of a mutable reference to towers.

then return ownership when it exits

There's no way to do that; for loops do not return anything.

Upvotes: 4

Related Questions