Pairwise Borrowing Values from a Vector

Hi,

I'm playing with writing a n-body simulation in Rust, just for practicing. In the code I need to compute the pairwise acting forces between to bodies. The bodies are stored in a vector of body-structs. However, the way I attempt it the borrow checker (rightfully) complains.
I have a simple testcode (Playground:

#[derive(Debug)]
struct Foo {
    val: i32,
    sum: i32
}

impl Foo {
    fn new(i: i32) -> Self {
        Foo {val: i, sum: 0}
    }
}

fn my_op(a: &mut Foo, b: &mut Foo) {
    a.sum = a.val + b.val;
    b.sum = a.val - b.val;
}

fn main() {
    let mut list:Vec<Foo> = Vec::new();
    for i in 0..3 {
        list.push(Foo::new(i));
    }
    println!("{:?}", list);
    for i in 0..list.len()-1 {
        for j in i+1..list.len() {
            my_op(&mut list[i], &mut list[j]);
        }
    }
    println!("{:?}", list);
}

As you can see I try to apply my_op to two elements from the vector, which cannot be equal due to the design of the nested loop indices (which the borrow checker does not seem to notice). I tried to work with iterators instead of nested loops to make it easier for the borrow checker, but I could not find any fitting method. How would you suggest I do this properly.

Thanks for your help

Here is one way, using slice patterns:

    let mut suffix = &mut list[..];
    while let [head, tail @ ..] = suffix {
        for other in tail.iter_mut() {
            my_op(head, other);
        }
        suffix = tail;
    }
4 Likes

for other in tail { also work as well.

1 Like

That doesn't compile, but this works:

for other in &mut *tail
2 Likes

Oh right, for loop is one of few places reborrowing doesn't work since it's generic with IntoIterator trait. You can avoid reassignment like bellow, though.

assert!(list.len() >= 2); // or use `if`
for offset in 0..list.len() - 2 {
    let (head, tail)) = list[offset..].split_first_mut().unwrap();
    for other in tail {
        my_op(head, other);
    }
}
2 Likes

Another way would be to use methods like split_first_mut() and split_at_mut() explicitly.

2 Likes

Thank you all for the suggestions. I will try them. From a first look I think I like the split_at_mut the best.

Just for reference, if someone looks up the topic in the future:
the offset loop has to end at list.len()-1.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.