I want to mutate Outer
struct using itself outside its implementation and without coping its attributes. How to implement it in Rust correctly? Is there a rustic way to have mutable and immutable references in the same time?
Here the code example (maybe this is far-fetched, but it illustrates the problem I face very good):
use std::sync::Mutex;
#[derive(Debug)]
struct Inner {
n: i64,
factor: i64,
}
#[derive(Debug)]
struct Max {
v: i64
}
#[derive(Debug)]
struct Outer {
inners: Vec<Inner>,
max: Max,
}
fn main() {
let mutex_s = Mutex::new(Outer {
inners: vec![
Inner { n: 1, factor: 2 },
Inner { n: 2, factor: 2 },
Inner { n: 3, factor: 3 },
Inner { n: 4, factor: 3 },
],
max: Max { v: 5 },
});
let mut s = mutex_s.lock().unwrap();
s.inners.retain(|i| i.n * i.factor < s.max.v);
println!("{:?}", s);
}
Here I get the following error: cannot borrow 's' as immutable because it is also borrowed as mutable
.
I guess here I need interior mutability, but I'm not sure how to implement it correctly, optimally and effectively.
If you need concurrent access to inners
and max
you need them to be in different Mutex
es, the Mutex
should be around the current type of inners
, (in your example max
is only accessed immutably so it doesn't need a Mutex
) not around the whole Outer
struct. In other words: for every field that you need to access simultaneously you need a different Mutex
, here that's just the inners
member:
#[derive(Debug)]
struct Outer {
inners: Mutex<Vec<Inner>>,
max: Max,
}
fn main() {
let s = Outer {
inners: Mutex::new(vec![
Inner { n: 1, factor: 2 },
Inner { n: 2, factor: 2 },
Inner { n: 3, factor: 3 },
Inner { n: 4, factor: 3 },
]),
max: Max { v: 5 },
};
s.inners.lock().unwrap().retain(|i| i.n * i.factor < s.max.v);
println!("{:?}", s);
}
Alternatively, if the fields are visible to you (they are pub
or Outer
is a local type) you can split the borrow:
fn main() {
let mutex_s = Mutex::new(Outer {
inners: vec![
Inner { n: 1, factor: 2 },
Inner { n: 2, factor: 2 },
Inner { n: 3, factor: 3 },
Inner { n: 4, factor: 3 },
],
max: Max { v: 5 },
});
let mut s = mutex_s.lock().unwrap();
// splitting the borrow into `inners` and `max` so only `max` is captured in the closure.
let Outer { inners, max } = &mut *s;
// or for more control over the mutability:
let Outer {
ref mut inners,
ref max,
} = *s;
inners.retain(|i| i.n * i.factor < max.v);
println!("{:?}", s);
}