Assigning and shrinking &mut to contained field

Hello,

let's say I own some t : T, and that I have a r : &mut Option<T> around.

What I want is to assign to r the value Some(t). However, afterwards, I do not need to modify r, but only care about the t now contained in r. I want a t2 : &mut T that is the T I just moved in, in order to for example recurse on it.

The only solution I found is the following:

*r = Some(t);
let t2 : &mut T = match r with {
  None => unreachable!("Some turned to None"),
  Some (tt) => tt 
}

The match, of course, is ugly. Is there a more canonical way to express this that does not involve dead code (and also not unsafe code, where I can just use an unreachable_unchecked!())?

In general, for an arbitrary enum type, you have to write something like that match, because the language has no concept of “this value was moved, but in a predictable, so please give me a new reference to it without checking”.

In the specific case, since this pattern does come up, Option::insert() does what you want. (See also get_or_insert_*() for when you want to keep the existing value if there is one.)

let t2 = r.insert(t);

(Also, if you had reason to write that match separately from the assignment, it can be expressed as r.as_mut().unwrap().)

4 Likes

Option::get_or_insert_with might be my favorite function in std. It's great for lazily growing tree-like data structures and things like that.

1 Like