Cannot borrow a mutable reference in struct

Hello, this is my first topic :slight_smile:

I'm struggling with a borrowing error in my tiny code. I have a User struct that has a name field. The set_name function of the User struct changes the name value to a new name and always returns true.

struct User {
    name: Option<String>,
}

impl User {
    fn new() -> Self {
        Self { name: None }
    }

    fn set_name(&mut self, new_name: &str) -> bool {
        self.name = Some(new_name.to_string());
        true
    }
}

The User struct is wrapped by UserService struct that has a user field. The set_user function creates a new user instance and sets its name to "Cake".

struct UserService {
    user: Option<User>,
}

impl UserService {
    fn new() -> Self {
        Self { user: None }
    }

    fn set_user(&mut self) -> bool {
        self.user = Some(User::new());
        self.user.as_ref().unwrap().set_name("Cake")
    }
}

The main function just creates a new UserService instance and prints a return value of the set_user function that is expected to be true.

fn main() {
    let mut user_service = UserService::new();
    println!("{}", user_service.set_user());
}

However, I got a cannot borrow data in a & reference as mutable error.

   Compiling playground v0.0.1 (/playground)
error[E0596]: cannot borrow data in a `&` reference as mutable
  --> src/main.rs:27:9
   |
27 |         self.user.as_ref().unwrap().set_name("Cake")
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable

error: aborting due to previous error

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

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

The whole code is on Rust Playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=23183e5aec32ca9237179c389f78ddda

I thought I took a mutable self.user.as_ref() via the &mut self keyword, but why can't I borrow the reference as mutable?

Option::as_ref returns Option<&T> - that's where the shared reference is. The thing you seem to want is Option::as_mut.

4 Likes

As a side note, another way to write this is with a match.

match &mut self.user {
    Some(user) => user.set_name("Cake"),
    None => false,
}

The difference is that when self.user is None, the match version will just return false, while the unwrap() version will panic at runtime. It also makes it more obvious that you are handling all the cases, whereas this isn't necessarily as obvious with a chain of .as_mut().unwrap().set_name("Cake").

Whether this is desired depends on your use case... Sometimes it's preferable to panic when something unexpected happens (i.e. we know that self.user should always be set by the time you call UserService::set_user()) because it immediately tells the developer they've introduced a bug.

1 Like