Confused about structs

I have written the following test and confused about the error message I'm getting:

1 struct Mystruct {
  2    username: String,
  3    email: String,
  4    phone: String,
  5 }
  6 
  7 impl Mystruct {
  8    fn set_name( &mut self, name: String ) {
  9       self.username = name;
 10    }
 11 
 12    fn get_name( &self ) -> String {
 13       self.username 
 14    }
 15 
 16 }
 17 
 18 fn main() {
 19    let mut ms = Mystruct{
 20       username: String::from("cybercrypt13"),
 21       email: String::from("cybercrypt13@hotmail.com"),
 22       phone: String::from("7705958748"),
 23    };
 24 
 25    println!("{}", ms.username );
 26    println!("{}", ms.email );
 27    println!("{}", ms.phone );
 28 
 29    ms.set_name( "Glenn Bob".to_string() );
 30    ms.phone = String::from("770-465-7879");
 31    println!("{}", ms.phone );
 32    println!("{}", ms.get_name() );
 33 
 34 }

Error message reads: move occurs because self.username has type String, which does not implement the Copy trait

I wasn't expecting that returning the value of a field would be so complicated. What exactly would you do to get this to work. After an hour of searching the Internet I haven't found a single example of how to do this.

Thanks,

Glenn

It's not complicated, but you have to understand the ownership model.

String is an owning type: it internally manages a growable heap buffer in which it actually stores its contents. Therefore, it has a destructor, and every String value must have exactly one owner (it can be assigned to a single variable, if that's how you like to call it). So, for example, if you assign the value of a String-typed variable to another one, the original one will be moved from and invalidated, so as to ensure that no double free occurs (this is one fundamental way of ensuring memory safety).

What your get_name() function tries to do in its current form is move out of the self.username field, since you are attempting to return the field by value. That can't possibly work, if you think about it: this would invalidate the field of self, but that's not allowed, because references (in this case, self) must always point to a value that is completely valid. (There are good reasons for this, but I'm not going to get into them now.)

What you have to decide is: how do you want to resolve this problem? Do you want to…

  1. return a reference to the field, or
  2. return a copy of the field?

If you want the former, you can declare the function to return a &String (by-ref) instead of a String (by-value), and return &self.username. If the latter, you can keep the signature unchanged and return self.username.clone(), explicitly copying the string.

1 Like

Thanks for the explanation and examples. I think I understand now.

Glenn

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.