Reputation: 67
If an instance of a struct is not declared as mut
, why it is still possible to move from a field of the struct? (at the same time it is not possible to move from an item of a vector even if the vector is declared as mut
).
Here is an example based on the one from the rust book:
#![allow(unused_variables)]
struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}
fn main() {
let user1 = User {
email: String::from("[email protected]"),
username: String::from("one123"),
active: true,
sign_in_count: 1
};
let s = user1.email;
println!("{0}", user1.email);
}
The issue is that the value from the field has been moved.
error[E0382]: borrow of moved value: `user1.email`
--> src/main.rs:19:21
|
18 | let s = user1.email;
| ----------- value moved here
19 | println!("{0}", user1.email);
| ^^^^^^^^^^^ value borrowed here after move
|
Why is that allowed? What is the motivation? Looks like const-correctness is broken for structs.
Upvotes: 2
Views: 103
Reputation: 211710
In Rust mutability means something more specific than "can't be changed", it means it can't be altered in its current form.
There are cases where you're not modifying it per-se, you're ripping it apart into its constituent elements, in which case the original has not been modified, it has been destroyed.
What you're doing here is asking to remove the email
property from that record, which Rust will gladly do for you, though at the expense of destroying the structure that property came from.
Once you start the process of dismantling an object, there is no going back. To avoid this you either make a copy, or use a reference.
let s = &user1.email;
println!("{0}", s); // Perfectly valid
println!("{0}", &user1.email); // Still valid, not affected
let t = user1.email.clone();
println!("{0}", t); // Independent copy
println!("{0}", &user1.email); // Still valid, not affected
Note, the only reason Rust tries to move this property is because it can. If you're working with a reference to that type you can't move anything, everything is automatically a reference, including user1.email
.
It is often the case in Rust that a function will receive an argument that contains a lot of information that needs to be moved into other locations. The most efficient way to do this is to often dismantle the argument given and move the parts into their desired locations.
Upvotes: 1