why we can move out String from struct field, but can't move via struct reference and can't move String from vec in Rust?

52 views Asked by At

I'm new to Rust and I find some behavior in Rust is not intuitive

say we have the code below:

struct User {
    name: String,
    email:String
}


fn main() {
    let some_vec = vec![String::from("value1"),String::from("value2")];
    
    let _v = some_vec[0];
    
    let user = User {
        name:String::from("name"),
        email:String::from("email")
    };
    
    let user_ref = &user;
    
    let _name = user_ref.name;
    
    let _email = user.email;
}

and the compiler complains that :

error[E0507]: cannot move out of index of `Vec<String>`
  --> src/main.rs:19:14
   |
19 |     let _v = some_vec[0];
   |              ^^^^^^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait
   |
help: consider borrowing here
   |
19 |     let _v = &some_vec[0];
   |              +

error[E0507]: cannot move out of `user_ref.name` which is behind a shared reference
  --> src/main.rs:28:17
   |
28 |     let _name = user_ref.name;
   |                 ^^^^^^^^^^^^^ move occurs because `user_ref.name` has type `String`, which does not implement the `Copy` trait
   |
help: consider borrowing here
   |
28 |     let _name = &user_ref.name;
   |                 +
  1. I think Vec and Struct are alike in grouping value together. so I thought if we can't move String from vec via index, we can't move String from struct field, either. but there is no error in let _email = user.email;
  2. I know we can't move out of a reference,like this:
    let v = vec![1, 2, 3];
    let v_ref: &Vec<i32> = &v;
    let v2 = *v_ref;// move occurs because `*v_ref` has type `Vec<i32>`, which does not implement the `Copy` trait

so the code let _name = user_ref.name is actually let _name = (*user_ref).name after the compiler dereference automatically ? it is a similar way to move out of a reference like the code above?

1

There are 1 answers

2
Masklinn On BEST ANSWER

I think Vec and Struct are alike in grouping value together.

They are not, because a "struct" is "transparent" to the compiler, as in the compiler is able to sus out different fields of a struct, that is not the case with indexing vec, which is an opaque operation. That is why you can uniquely borrow different fields of a struct, but not different indices of a vec.

there is no error in let _email = user.email;

That's because it's performing a partial move out of the struct, afterwards you can neither pass around user itself as a unit (e.g. as a parameter to a function):

error[E0382]: use of partially moved value: user

nor access user.email:

error[E0382]: use of moved value: user.email

you can only access the other fields of the structure.

so the code let _name = user_ref.name is actually let _name = (*user_ref).name after the compiler dereference automatically ?

That is what automatic dereference means, yes. It dereferences, automatically.