我正在编写一个小游戏;我有一个怪物矢量,一个怪物可以对所有其他怪物造成伤害。我需要一个函数来获取所有怪物的矢量和对攻击怪物的引用。
我理解为什么对于Rust的类型系统来说这是不可能的:我需要对向量的可变引用和对怪物的可变引用,但这是不可能的,因为怪物属于向量。我找不到解决方法。
struct Monster {
life: i32,
}
// give 1 damage to all except me
// increase my life by 1
fn give_1_damage(me: &mut Monster, all: &mut Vec<Monster>) {
for m in all {
m.life -= 1;
}
me.life += 2;
}
fn main() {
let mut a = vec![Monster { life: 3 }, Monster { life: 3 }];
let ref mut b = &mut a[0];
give_1_damage(b, &mut a);
}
Lukas Kalbertodt proposes传递向量中怪物的偏移量。这很棒,谢谢!但实际上我的代码更复杂:
struct Monster {
life: i32,
}
struct Game {
player1: Vec<Monster>,
player2: Vec<Monster>,
}
fn give_1_damage(player_idx: usize, monster_idx: usize, game: &mut Game) {
// ...
}
我知道可以传递玩家的索引和怪物的索引,但我发现这很难看。我是否真的需要通过player_idx
和monster_idx
,而我以前知道哪个怪物在攻击,我可以参考它?
答案 0 :(得分:2)
最简单的方法是传递索引而不是引用:
#[derive(Debug)]
struct Monster {
life: i32,
}
// give 1 damage to all except me
// increase my life of 1
fn give_1_damage(monsters: &mut [Monster], me: usize) {
for (i, m) in monsters.iter_mut().enumerate() {
if i == me {
m.life += 1;
} else {
m.life -= 1;
}
}
}
fn main() {
let mut a = vec![Monster{life: 3}, Monster{life: 3}];
println!("a: {:?}", a);
let b = 0;
give_1_damage(&mut a, b);
println!("a: {:?}", a);
}
此外,由于您没有向怪物列表中添加任何内容,因此您应该使用&mut [Monster]
而不是&mut Vec<Monster>
;这种方式更通用。
答案 1 :(得分:2)
欢迎来到Rust!正如您已经注意到的那样,Rust类型系统(更具体地说:借用检查器)不会让您这样做。在Rust中,您必须以不同于您习惯的方式来思考某些问题。这实际上是一个好主意。
例如,让我们来看看你的代码:为了增加生命&#34;通过1,你在循环之外将它增加2,因为循环会将它减少1.这不是编写这样的代码的好方法,因为现在代码的不同部分是语义连接的,尽管它们不应该是#。是的。
那么你怎么能在Rust中做到这一点?
有多种方法可以做到这一点,但是这一点(评论中的解释):
#[derive(Debug)]
struct Monster {
life: i32,
}
// Instead of passing a mutable reference, we just pass the index of the
// attacking monster in the vector.
// Note that I also pass `&mut [...]` instead of `&mut Vec<...>`. This is
// sufficient as long as you only want to mutate single elements.
fn give_1_damage(me_idx: usize, all: &mut [Monster]) {
// Here we split the vector in three parts: the part from the
// beginning to the attacking monster, the attacking monster itself,
// and the rest of the slice.
let (front, me, back) = {
// This is done by using those two special methods of slices.
let (first, second) = all.split_at_mut(me_idx);
let (me, rest) = second.split_first_mut().unwrap();
(first, me, rest)
};
// Here we chain together the two parts and iterate over all monsters
// except for the attacking one!
for m in front.into_iter().chain(back) {
m.life -= 1;
}
me.life += 1;
}
fn main() {
let mut a = vec![Monster { life: 3 }, Monster { life: 3 }];
give_1_damage(0, &mut a);
println!("{:?}", a);
}
您可以尝试here。