Reputation: 107
I have a 2D Vec and want to get two mutable references from it at the same time, here is the demo code
use std::default::Default;
#[derive(Default, Clone, PartialEq)]
struct Ele {
foo: i32,
bar: f32,
}
fn main() {
let mut data:Vec<Vec<Ele>> = vec![vec![Default::default();100];100];
let a = &mut data[1][2];
let b = &mut data[2][4];
if a != b {
a.foo += b.foo;
b.bar += a.bar;
}
}
Use unsafe code is OK.
Upvotes: 0
Views: 72
Reputation: 8678
You shouldn't try to solve this problem using unsafe, but rather by understanding why the compiler doesn't allow you to do something that looks alright, and what are the available tools to convince it (without hiding it behind a black box and just saying "trust me") it's a genuine thing to do (usually these tools will themselves use unsafe code, but since it's behind a safe boundary it's the burden of the writer of these tools to ensure everything works fine even when the compiler can't figure it out on its own, which is better that having this burden yourself).
In particular, Rust doesn't understand that you are accessing two separate region of memory; being conservative, it just assumes that if you are using a single element of an array, it must consider you are using it all. To make it clear you are talking about two separate pieces of an array, the solution is simply to split the array into two distinct pieces. That way, you make it clear that they are different memory regions:
use std::default::Default;
#[derive(Default, Clone, PartialEq)]
struct Ele {
foo: i32,
bar: f32,
}
fn main() {
let mut data:Vec<Vec<Ele>> = vec![vec![Ele::default();100];100];
let (left, right) = data.split_at_mut(2);
let a = &mut left[1][2];
let b = &mut right[0][4];
if a != b {
a.foo += b.foo;
b.bar += a.bar;
}
}
Note that this will not actually split the vector, it will only give two views over the vector that are disjoint, so it's very efficient.
See the playground.
Upvotes: 3