两个可变借用向量

问题描述 投票:0回答:3

我正在学习用 Rust 编写的突破游戏教程,我有简单的数据结构来表示屏幕上的球:

pub struct Ball {
    rect: Rect,
    vel: Vec2,
}

它存储在向量中

let mut balls: Vec<Ball> = Vec::new();

但是,当我尝试计算球与球的碰撞时,我遇到错误:

 --> src/main.rs:193:31
    |
192 |         for ball in balls.iter_mut() {
    |                     ----------------
    |                     |
    |                     first mutable borrow occurs here
    |                     first borrow later used here
193 |             for other_ball in balls.iter_mut() {
    |                               ^^^^^^^^^^^^^^^^ second mutable borrow occurs here
// ball collision with balls
        for ball in balls.iter_mut() {
            for other_ball in balls.iter_mut() {
                if ball != other_ball {
                    resolve_collision(&mut ball.rect, &mut ball.vel, &other_ball.rect);
                }
            }
        }

我最初的方法是使用双重迭代,现在我知道借用检查器不允许我修改向量,因为它被认为是不安全的。我可以使用通用模式来解决此类问题吗?

rust borrow-checker
3个回答
1
投票

您可以使用

split_at_mut
来实现此目的。感觉有点老套,但效果还不错。这是一个获取两个不同可变值的实现。

pub fn get_mut2<T>(v: &mut [T], i: usize, j: usize) -> Option<(&mut T, &mut T)> {
    if i == j {
        return None;
    }
    let (start, end) = if i < j { (i, j) } else { (j, i) };

    let (first, second) = v.split_at_mut(start + 1);
    Some((&mut first[start], &mut second[end - start - 1]))
}

pub fn main() {
    let mut data = [0, 1, 2, 3, 4, 5, 6, 7];
    let (a, b) = get_mut2(&mut data, 3, 6).unwrap();
    *a += 10;
    *b += 10;
    eprintln!("{:?}", data); // [0, 1, 2, 13, 4, 5, 16, 7]
}

playground上有一个工作版本。

然后您需要对数组长度进行双循环:

assert!(!a.is_empty());
for i in 0..a.len()-1 {
  for j in i..a.len() {
    let (ball_i, ball_j) = get_mut2(&mut a, i, j).unwrap();
    ...
  }
}

请注意,我的循环确保我只访问每个无序对一次。


1
投票

您可以使用

RefCell
实现可变性,并使用
iter()
代替
iter_mut()
,这样编译器就不会抱怨代码借用了 vec 两次,例如:

struct Ball(u32, u32);

let mut balls = vec![];

balls.push(RefCell::new(Ball(0, 0)));
// push more balls into vec

for b1 in balls.iter() {
    for b2 in balls.iter() {
        // change attributes of a ball
        b1.borrow_mut().0 = 10;
        b2.borrow_mut().1 = 20;
    }
}

0
投票

split_at_mut
给你两片,所以你有两件事可以做。

pub fn main() {
    let mut data = vec!["a", "b", "c", "d", "e"];
   
    for i in 1..data.len() {
        let (left, right) = data.split_at_mut(i);
        let a = &mut right[0];
        for b in left.iter_mut() {
            println!("{a} {b}");
        }
    }
}

这假设您的碰撞是传递的:如果您将 A 与 B 进行比较,则不需要同时将 B 与 A 进行比较。

© www.soinside.com 2019 - 2024. All rights reserved.