Problem borrowing two elements of vec mutably

I have been using Rust for a while now and haven’t run into a borrowing issue that I couldn’t work around for quite some time. However, I’ve just run into this issue that I can’t seem to get past. I have a function that takes two parameters, each are mutable references. I want to supply the parameters with data from the same vector, and as a result I am getting a ‘Can’t borrow… as mutable more than once at a time’ error. Here is a minimal code representation of what I’m doing:

fn main() {
    let mut data = vec![];
    data.push(Something{a: 54.8, b: 43.9 });
    data.push(Something{a: 34.8, b: 23.9 });
    do_something(&mut data[0], &mut data[1]);
}

fn do_something(c: &mut Something, d: &mut Something) {
    c.a += 1.0;
    d.b += 1.0;
}

struct Something {
    a: f64,
    b: f64,
}

Any ideas? Honestly, I get the feeling that I’m trying to do something foolish and that there is a simple fix that I’m just not seeing.

1 Like

Don’t worry, this actually isn’t simple. But you can split it and then index the separate slices.

If you really just want 0 and 1, then you can use:

let (first, tail) = data.split_first_mut().unwrap();
do_something(first, &mut tail[0]);

If you want some arbitrary indexes i and j, assuming i < j:

let (head, tail) = data.split_at_mut(i + 1);
do_something(&mut head[i], &mut tail[j - i - 1]);

Have you tried split_at_mut? It worked for me in a similar situation. In my case the split point was determined by a variable, so I wasn’t surprised that the compiler couldn’t tell the indices were distinct.

FWIW, the compiler doesn’t even try to determine this. Indexing a slice or vector always counts as borrowing the whole thing, and then you’re prevented from indexing a second borrow. The trick is that split_at_mut uses unsafe code to give you back distinct slices, and split_first_mut that I mentioned is just based on split_at_mut(1).

3 Likes

Thank you all for your response. I’ll see about your solutions. To tell you the truth, I’m somewhat comforted in the knowledge that this isn’t a straightforward situation because I am, at this point, not exactly a Rust newbie (I have well over 120k sloc under my belt) and I kind of felt like this was a novice mistake I was making.

1 Like

Have you thought of passing the whole data like so do_something(&mut data); and allowing your function to do the needful? Like so:
fn do_something(s: &mut Vec<Something>) { s[0].a += 1.0; s[1].b += 1.0; }

I believe it should give you same result expect there is a reason you want it passed individually. In that sense, you really don’t need your struct in the vector. I might be wrong but just saying. Hope this helps.

@2teez That would be a wonderful idea and it could work nicely. I might try this as the way forward. Thanks again to everyone for your quick answers.

1 Like

Could also do fn do_something(s: &mut [Something]) { s[0].a += 1.0; s[1].b += 1.0; } if you want it to accept more things than Vecs.