这是我的问题的简化视图:
struct Game {
currentPlayer: u8,
players: Vec<Player>,
units: Vec<Unit>,
}
fn update(game: &mut Game) {
for unit in game.units.iter_mut().filter(|u| u.owner == game.currentPlayer) {
if unit.repairPrice < game.getPlayer(game.currentPlayer).money {
unit.health = 100;
game.getPlayer(game.currentPlayer).money -= unit.repairPrice;
}
}
}
impl Game {
pub fn getPlayer(&mut self, player: u8) -> &mut Player {
return self.players.iter_mut().find(|p| p.color == player).unwrap();
}
}
在这里,编译器说我不能借用不可变的值 currentPlayer,因为游戏已经借用为可变的。
虽然我理解编译器在说什么以及为什么这么说,但我不知道我应该改变什么。单位和播放器都必须同时更新,所以看起来无论我怎么做总是会产生冲突。
我可以克隆整个结构,对其进行迭代和计算,然后在原始可变结构中找到相应的单位和玩家来更新它们,但这是非常低效的。
将您的代码扩展为问题的重现器,很明显,如果没有:,您就无法完成这项工作
unsafe
的东西,或者
getPlayer
的代码内联到
update
(冗余,糟糕)
它借用了该对象的整个。因此,对于 getPlayer
,即使
you知道它只触及
players
属性,Rust 的借用检查器(适用于函数 interfaces,而不是 contents)必须假设它可以对
Game
执行任何操作收到的参考。我能想到的最小解决方案是使 getPlayer
成为一个自由函数,它只接受对
Vec
对象的 Player
的可变引用,因此 update
可以通过以下方式进行分析:明确表示 Vec
都不会被多次借用。fn update(game: &mut Game) {
for unit in game.units.iter_mut().filter(|u| u.owner == game.currentPlayer) {
// Passed mutable reference to the players only, rather than being called on a whole Game
if unit.repairPrice < getPlayer(&mut game.players, game.currentPlayer).money {
unit.health = 100;
// Same change as above
getPlayer(&mut game.players, game.currentPlayer).money -= unit.repairPrice;
}
}
}
// Made a free function so it can accept the Vec alone, not the whole game
fn getPlayer(players: &mut Vec<Player>, player: u8) -> &mut Player {
return players.iter_mut().find(|p| p.color == player).unwrap();
}
工作正常(尽管它确实抱怨你的非惯用变量名称;
snake_case
FTW,这些mixedCase
都不是废话)。
Vec<Unit>
附加到 each
Player
,而不是将其放在 Game
上,而不是与玩家分开管理单位。这样做, getPlayer
不会与 update
发生冲突,因为您只需可变地获取单个 Player
对象,并对附加到它的 unit
进行操作(而不接触 的任何其他元素) Game
,并且操作更高效,因为您不需要继续查找玩家,不需要处理每个单位,只需处理该玩家的单位,等等)。如果您需要将所有 Unit
作为迭代器进行遍历,则简单的 flat_map
可以让您迭代玩家并将他们的单位组合成单个逻辑迭代器。