Archsx
Archsx

Reputation: 972

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?

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?

Upvotes: 0

Views: 72

Answers (1)

Masklinn
Masklinn

Reputation: 42342

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.

Upvotes: 2

Related Questions