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.