Theme
Q032. How does ownership work for struct fields?
Short Answer
A struct owns fields stored by value, so moving a non-Copy struct transfers its ownership tree and dropping it recursively destroys initialized fields. An owned field can be moved out when permitted, leaving a partial move; borrowed fields cannot be moved out directly. Copy fields may be copied independently, and reference fields borrow rather than own their referents.
Deep Dive
Field types define the ownership relationship:
StringorVec<T>fields are owned by the struct;&'a Tfields contain owned reference values but borrow the referent;Box<T>owns its allocation and containedT;Rc<T>andArc<T>represent counted shared ownership.
Moving the whole struct makes its source unavailable, even if some fields are Copy, unless the struct itself implements Copy. Moving one non-Copy field out of an owned struct creates a partial move, while untouched fields remain individually usable.
A type implementing Drop generally does not allow individual fields to be moved out because its destructor expects a valid complete self. Replacement APIs can transfer a field while preserving that invariant.
Internal Model
rustc models fields as place projections such as request.path and request.body. Move analysis can track their initialization separately when the parent type permits partial moves.
Generated drop glue follows the same ownership tree, skipping moved-out fields and destroying remaining fields in declaration order.
Example
rust
struct Request {
path: String,
body: Vec<u8>,
}
fn send(request: Request) {
println!("{}: {} bytes", request.path, request.body.len());
}
fn main() {
let request = Request {
path: String::from("/orders"),
body: vec![1, 2, 3],
};
send(request);
// println!("{}", request.path); // error: request was moved
}Common Mistakes
- Assuming a struct borrows every heap allocation referenced by its fields.
- Expecting an owned field to remain available after moving the whole struct.
- Manually dropping fields inside
Drop::dropeven though drop glue will drop them afterward.
Follow-ups
- Why can a type implementing
Dropnot usually be partially moved? - How does a reference field differ from an owning smart-pointer field?
- How can one field be extracted through
&mut selfsafely?
Related
- Q006. What is the difference between an owner, a binding, a value, and a resource?
- Q016. What is a partial move?
- Q034. How can you safely extract an owned value using
Option::take,mem::take, ormem::replace?
References
- The Rust Programming Language
- Rust Reference
- Rust Standard Library