Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I mutably borrow a primitive from an enum?

I would like to be able to obtain references (both immutable and mutable) to the usize wrapped in Bar in the Foo enum:

use Foo::*;

#[derive(Debug, PartialEq, Clone)]
pub enum Foo {
    Bar(usize)
}

impl Foo {
    /* this works */
    fn get_bar_ref(&self) -> &usize {
        match *self {
            Bar(ref n) => &n
        }
    }

    /* this doesn't */
    fn get_bar_ref_mut(&mut self) -> &mut usize {
        match *self {
            Bar(ref mut n) => &mut n
        }
    }
}

But I can't obtain the mutable reference because:

n does not live long enough

I was able to provide both variants of similar functions accessing other contents of Foo that are Boxed - why does the mutable borrow (and why only it) fail with an unboxed primitive?

like image 310
ljedrz Avatar asked May 20 '17 18:05

ljedrz


2 Answers

These examples show the sample problem:

fn implicit_reborrow<T>(x: &mut T) -> &mut T {
    x
}

fn explicit_reborrow<T>(x: &mut T) -> &mut T {
    &mut *x
}

fn implicit_reborrow_bad<T>(x: &mut T) -> &mut T {
    &mut x
}

fn explicit_reborrow_bad<T>(x: &mut T) -> &mut T {
    &mut **&mut x
}

The explicit_ versions show what the compiler deduces through deref coercions.
The _bad versions both error in the exact same way, while the other two compile.

This is either a bug, or a limitation in how lifetimes are currently implemented in the compiler. The invariance of &mut T over T might have something to do with it, because it results in &mut &'a mut T being invariant over 'a and thus more restrictive during inference than the shared reference (&&'a T) case, even though in this situation the strictness is unnecessary.

like image 84
eddyb Avatar answered Sep 28 '22 15:09

eddyb


You need to replace Bar(ref mut n) => &mut n with Bar(ref mut n) => n.

When you use ref mut n in Bar(ref mut n), it creates a mutable reference to the data in Bar, so the type of n is &mut usize. Then you try to return &mut n of &mut &mut u32 type.

This part is most likely incorrect.

Now deref coercion kicks in and converts &mut n into &mut *n, creating a temporary value *n of type usize, which doesn't live long enough.

like image 45
red75prime Avatar answered Sep 28 '22 14:09

red75prime