Borrow mutably, then borrow mutably again


#1

The following code will complain that change2 is evil and trying to share &mut self around.

fn main() {}

struct Me;
struct ChangeMe<'a>(&'a mut Me, usize);

fn change1(x: &mut Me) -> Option<ChangeMe> {
    Some(ChangeMe(x, 1))
}

fn change2(x: &mut Me) -> ChangeMe {
    change1(x).unwrap_or_else(move || ChangeMe(x, 2))
}

(playground link)

Is there something fundamentally unsafe about what change2 is doing? Or is there perhaps some obvious way to cleanly express this that I’m missing?

I sort of get that change1 can only accept one lifetime, and that because its value might be returned, that lifetime has to be as long as the function, which means it subsumes the unwrapping part. But it looks like a fairly safe operation…


#2

There’s nothing fundamentally unsafe about this - it’s just the borrowck can’t reason about unwrap_or_else and the interplay with what the closure there captures.

Personally, I’d just add a slight dusting of unsafe and call it a day:

fn change2(x: &mut Me) -> ChangeMe {
    let raw = x as *mut _;
    change1(x).unwrap_or_else(move || ChangeMe(unsafe { &mut *raw }, 2))
}

Alternatively, see if you can restructure your code/functions so you don’t hit this scenario. For example, change1 might take a closure to compute the right value if it’s going to return None.