Binding modes are making this painful. If you want thing
to be a u32
, you could do
let ref mut loc @ Smth(thing) = *val;
But in general I think this binding is confusing and that you should do one of
let loc = val; // Assuming you want the new name for some specific reason
let thing /* : u32 */ = loc.0;
Same thing basically:
let thing /* : u32 */ = val.0;
let loc = val; // Assuming you want the new name for some specific reason
Or if you want thing
to be a &mut u32
:
let loc = val; // Assuming you want the new name for some specific reason
let thing /* : &mut u32 */ = &mut loc.0;
In this last case, once you use loc
again, you can't use thing
anymore.
For any of these, you could do
let loc = &mut *val;
In order to reborrow val
instead of moving it.
On a higher level, this is an example of "match ergonomics" being unergonomic / confusing. Another name for the behavior is "binding modes". You can read some documentation on binding modes here.
In your original, your non-reference pattern loc
made the default binding mode ref mut
, so on the inside, thing
was taken to be a &mut u32
. However, it couldn't reconcile the borrow on the inside with moving val
into loc
(where is above, the borrow on the inside is taken after the move). One fix is to first move val
and then mutably borrow the contents from loc
.
This non-working version is similar, but it acts on a reborrow of val
instead of a move. It still doesn't work because both bindings are trying to borrow from val
, as opposed to thing
borrowing from loc
, say.
let ref mut loc @ Smth(ref mut thing) = *val;
Similar to before, one possible fix is to first make loc
a reborrow, and then to borrow thing
from inside loc
.
And finally, the working version where thing
is a u32
works because the outermost ref mut
disables the resetting of the default binding mode; it remains "move", so thing
is taken to be a u32
.