struct Person {
name: String,
gender: String,
age: u32,
}
let p1 = Person {
name: String::from("Tom"),
gender: String::from("male"),
age: 44,
};
let vec = Vec::new();
vec.push(p1);
let person = vec[0];
The last line will result in compile error. I realized the last line transferred ownership from vector to another variable, which could ruin the original vector, but still curious about what is behind the scene.
As I know we can move member of self defined struct.
You can't do a move using an indexing op because they are defined using references. Rust is notably missing a move reference, so you can't use an indexing op to move out of a vector.
You can do vec.remove(0) to take something out of a vector, or if you are removing from the end you can do vec.pop().
indexing is controlled via Index and IndexMut and vec[idx] is desugarred like so
*vec.index(idx)
or
*vec.index_mut(idx)
depending on context. Note the dereference at the start, this is why you must add a & to get a borrow.
For Copy types, they can be copied out because dereferencing a borrow to a Copy type copies the pointee, but if the pointee does not implement Copy (like Person or String) then it can't be copied out. So you must use normal methods on Vec<_> to move them out of the Vec<_>
That is correct. Move out of vector is not allowed to leave a "hole" in the vector. The reason why it works for structs is that there is only a finite small number of fields, so the compiler can track validity of each field. A vector may have 2^63 entries, and that's too much to track automagically.
You can use remove() or swap_remove() to prevent the "holes". You can use Vec<Option<Person>> and vec[0].take() to explicitly track which elements were removed.