可变结构体在向量中的应用

14

我正在尝试创建一个向量,用于在游戏中跟踪敌人,它将持有一堆可变结构体。我有一个世界结构体,其中包含敌人作为其成员,如下所示:

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

我按照以下方式创建敌人向量:

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

稍后在代码中,当我从enemies中选出一个敌人进行攻击并尝试更新其hp时,如下:

在代码的后续部分,当我从enemies中选择一个敌人进行攻击,并尝试按以下方式更新它的hp:

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

问题出在这里,因为敌人在这一点上显然是不可变的

 error: cannot assign to immutable field `enemy.hp`
2个回答

14

已更新至最新的 Rust 版本

Rust 中的可变性与数据结构无关,它是存储数据的位置(即变量)的属性。也就是说,如果您将一个值放在可变的槽中:

let mut world = World::new();

然后,您可以获取对此变量的可变引用,因此调用可以突变它的方法。

您的结构体拥有其包含的所有数据,因此您可以随时将其变为可变状态。self.enemies.iter()返回一个生成类型为&Creature的不可变引用项的迭代器,因此您无法使用它们来突变结构体。但是,向量上还有另一种方法,称为iter_mut()。此方法返回一个产生&mut Creature - 可变引用的迭代器,它允许更改它们指向的数据。

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;
  }
}

请注意,为了使这个工作起来,你必须通过可变引用传递self,否则将无法在其下面进行任何修改,这意味着您将无法获得结构体内部的可变引用,包括向量中的项。简而言之,请确保包含此循环的方法定义如下:

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

mut_iter()解决了问题(我的示例不够清晰,但实际上我传递的是&mut self):) - Lindsey B
请注意mut_iter现已更名为iter_mut - Cam Jackson

1

Vec<T>::iter()会给你一个Iterator<&T>1,也就是一个“不可变借用”指针的迭代器。如果你想改变内容,请使用Vec::iter_mut(),它是一个Iterator<&mut T>

通常情况下,mut的存在或缺失影响你是否能使用某些方法,但并不影响每个方法的含义。这并不是全部真相(也许对于&&mut实现了同名方法的不同特性),但这是一个很好的近似值。

1我省略了这些类型的生命周期方面,以说明一个观点。


请注意,mut_iter 现在被称为 iter_mut - Cam Jackson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接