Mutable structs in a vector

▼魔方 西西 提交于 2021-01-27 02:16:44

问题


I'm trying to create a vector to keep track of enemies in a game that will hold a bunch of mutable structs. I have a world struct that has the enemies as a member of it as follows:

pub struct World {
  pub player      : Creature,
  pub enemies     : Vec<Creature>,
}

I create the enemies vector as follows:

 let mut enemies = vec![];
 let mut enemy = Creature::new(5, 5, map_start_x+5, map_start_y+5, "$", 10, 1, "")
 enemies.push(enemy);

later on in the code when I pull out an individual enemy from enemies for attacking and try to update the hp as follows:

  for enemy in self.enemies.iter() {
    if new_x == enemy.x && new_y == enemy.y {
      enemy.hp -= self.player.damage;
      return;
    }
  }

which is where the problem occurs since enemy is apparently not mutable at this point

 error: cannot assign to immutable field `enemy.hp`

回答1:


Updated for the latest Rust version

Mutability in Rust is not associated with data structures, it is a property of a place (read: a variable) where the data is stored. That is, if you place a value in a mutable slot:

let mut world = World::new();

then you can take mutable references to this variable, and hence call methods which can mutate it.

Your structure owns all data it contains, so you can make it mutable any time you need. self.enemies.iter() returns an iterator which generates items of type &Creature - immutable references, so you can't use them to mutate the structure. However, there is another method on a vector, called iter_mut(). This method returns an iterator which produces &mut Creature - mutable references, which do allow changing data they point to.

for enemy in self.enemies.iter_mut() {
  if new_x == enemy.x && new_y == enemy.y {
    enemy.hp -= self.player.damage;
    return;
  }
}

// The following also works (due to IntoIter conversion)
for enemy in &mut self.enemies {
  if new_x == enemy.x && new_y == enemy.y {
    enemy.hp -= self.player.damage;
    return;
  }
}

Note that in order for this to work, you have to pass self by mutable reference too, otherwise it will be impossible to mutate anything under it, implying that you won't be able to obtain mutable references to internals of the structure, including items of the vector. In short, make sure that whatever method contains this loop is defined like this:

fn attack(&mut self, ...) { ... }



回答2:


Vec<T>::iter() gives you an Iterator<&T> 1, i.e. an iterator over "immutable borrowed" pointers. If you want to mutate the contents, use Vec::iter_mut(), which is an Iterator<&mut T>.

In general, presence or absence of mut affects whether you can use some method, but not what each method means. This is not the whole truth (perhaps different traits with a method of the same name are implemented for & and &mut), but it's a good approximation.

1 I omitted the lifetime aspect of these types to make a point.



来源:https://stackoverflow.com/questions/23585651/mutable-structs-in-a-vector

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!