Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Move behind mutable reference in a struct

I have a struct containing a mutable reference and an owned value. I’m trying to see if I can implement some getters for these values. To my surprise, getx compiles but gety doesn’t. Given that neither &mut String nor String implements Copy, why would the compiler allow getting a &mut String but not a String?

struct S<'a> {
    x: &'a mut String,
    y: String,
}
impl<'a> S<'a> {
    fn getx(&mut self) -> &mut String {
        self.x // Ok
    }
    fn gety(&mut self) -> String {
        self.y // Err
    }
}

Error messages:

error[E0507]: cannot move out of self.y which is behind a mutable reference

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

move occurs because self.y has type String, which does not implement the Copy trait

>Solution :

In the gety example you move out of the String. You can’t do that because the ownership would be given to the caller, leaving the original struct in a partial state (it still needs to be usable because you only borrow yourself mutably via &mut self).

As @PitaJ correctly said, the getx example works via implicit reborrowing. This concept is not documented enough (and there is an issue for it), but it can be explained pretty easily:

When the compiler knows the type of a variable to be a (mutable) reference, it can be automatically borrowed (mutably). In this case a reborrow occurs, meaning that the expression first gets dereferenced like this:

fn getx(&mut self) -> &mut String {
    &mut *self.x
}

Or, with explicit lifetime annotations:

fn getx<'s>(&'s mut self) -> &'s mut String {
    &mut *self.x
}

This works, because it returns a mutable reference to the String’s contents, but not the mutable reference stored in the container. Because this returns a exclusive reference to the inner String, it is not possible to change the String in another way while this reference is in scope. This is one of the most fundamental aspects of Rust’s ownership model.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading