21.18 Partial Moves in Patterns (Advanced)
When a pattern destructures a type that does not implement Copy
(like String
, Vec
, Box
), binding a field by value moves that field out of the original structure. Rust permits partial moves: moving some fields while borrowing others (ref
or ref mut
) within the same pattern.
struct Message { id: u64, content: String, // Not Copy metadata: Option<String>, // Not Copy } fn main() { let msg = Message { id: 101, content: "Important Data".to_string(), metadata: Some("Source=SensorA".to_string()), }; match msg { // Move `content`, borrow `id` and `metadata` using `ref` Message { id: ref msg_id, content, metadata: ref meta } => { println!("Processing message ID: {}", msg_id); // Borrowed `id` as `&u64` println!("Moved content: {}", content); // Moved `content`, now owned here println!("Borrowed metadata: {:?}", meta); // Borrowed `metadata` as `&Option<String>` // `msg` itself cannot be fully used after this point because `content` // was moved out. Accessing `msg` directly would be a compile error. // However, accessing fields *not* moved (like `msg.id` or `msg.metadata`) // *might* theoretically be possible if they weren't also borrowed by `ref`. // In practice, you work with the bindings (`msg_id`, `content`, `meta`). } } // Error: `msg` cannot be used here because `msg.content` was moved. // println!("Original message ID: {}", msg.id); // Compile error: use of partially moved value: `msg` }
After a partial move, the original variable (msg
in this case) is considered “partially moved”. It cannot be used as a whole, preventing potential use-after-move errors for the moved fields. This feature allows fine-grained ownership control during destructuring, potentially avoiding unnecessary clones when only parts of a structure need to be owned.