Question about ownership with

I am trying to understand ownership with references in rust.
Considering the following example:

struct V { v: usize }

impl V {
    fn new() -> Self {
        Self{ v: 0 }
    }
}

struct S { v: V }

impl S {
    fn new(value: V) -> Self {
        Self { v: value }
    }

    fn change(&mut self, value: usize) {
        self.v.v = value;
    }
}

struct SRef<'a> { v: &'a mut V }

impl<'a> SRef<'a> {
    fn new(v: &'a mut V) -> Self {
        Self { v }
    }

    fn change(&'a mut self, value: usize) {
        self.v.v = value;
    }
}

fn main() {
    let v = V::new();
    let mut v_ref = V::new();

    let mut s_ref = S::new(v);
    s_ref.change(1);
    s_ref.change(2);
    s_ref.change(3); // Why this works ...

    let mut s = SRef::new(&mut v_ref);
    s.change(1);
    s.change(2); // While this throws a borrow error?
}

The full error is:

error[E0499]: cannot borrow `s` as mutable more than once at a time
  --> src/main.rs:49:5
   |
47 |     s.change(1);
   |     - first mutable borrow occurs here
48 | 
49 |     s.change(2); // While this throws a borrow error?
   |     ^
   |     |
   |     second mutable borrow occurs here
   |     first borrow later used here

error: aborting due to previous error

For more information about this error, try `rustc --explain E0499`.
error: could not compile `playground`

To learn more, run the command again with --verbose.

What happens here is that SRef::change borrows &mut self for the same 'a lifetime as SRef, meaning that the SRef is still considered borrowed due to the first .change() call at the second .change() call. The fix would be to change the function signature to fn change(&mut self, value: usize) without the 'a.

2 Likes

Omg, of course.. thanks so much for going over that and explaining to me.

1 Like

In general, &'a mut Stuff<'a> is an anti-pattern and probably useless/never what you really need. (Here this kind of type manifests when you declare &'a mut self, because then self is &'a mut SRef<'a> and &mut self.v is &'a mut &'a mut V.)

4 Likes

Got it, thanks for the explanation. :smiley:

I've seen a bunch of questions about this anti-pattern. Can the compiler produce a warning the way it does for not using a Result ? Is there a lint for it? If not, should there be?

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.