Prepare for some borrow-workaround-gymnastics…
So, I can make a nice little count-with-mutable-pointer program as follows.
fn incr(p: &mut i32) { *p += 1; }
fn main() {
let mut x = 0;
for _ in 0..10 {
incr(&mut x);
println!("x: {}", x);
}
}
Rust is quite happy to work out the lifetimes if we introduce an extra mut pointer, p
. From a data point-of-view, it gets copied; from the lifetime point-of-view maybe p
gets mutably borrowed and this dereferenced (this is the key point to the rest of the problem, and I don’t fully understand it).
fn incr(p: &mut i32) { *p += 1; }
fn main() {
let mut x = 0;
let mut p = &mut x;
for _ in 0..10 {
incr(p);
println!("x: {}", *p);
}
}
Lets make things more interesting by making p
optional:
fn incr(p: Option<&mut i32>) {
if let Some(q) = p {
*q += 1;
}
}
fn main() {
let mut x = 0;
let mut p = Some(&mut x);
for _ in 0..10 {
// uh oh... how do we pass p?
incr(p); // doesn't work
println!("x: {}", *p.as_ref().unwrap_or(&&mut 0));
}
}
It turns out we can make this work, by unwrapping and rebuilding the option:
if let &mut Some(ref mut q) = &mut p {
incr(Some(q));
}
or like this:
incr(p.as_mut().map_or(None, |p| Some(p)));
But this stuff is nasty to get your head around. Why doesn’t incr(p)
work? Should incr(p.clone())
work? Or should Option
have some other method, supporting incr(p.foo())
?