Theme
Q033. How do enums and pattern matching affect ownership?
Short Answer
An enum owns the fields of its active variant. Pattern matching inspects the discriminant and then moves, copies, or borrows bound fields according to their types and binding modes. Binding a non-Copy field by value moves it; matching through a reference borrows it. Only fields of the active variant are destroyed when the enum is dropped.
Deep Dive
Patterns are ownership operations, not only control flow. A binding such as Message(text) binds text by value and moves a String from an owned enum. Message(ref text) borrows the field, while matching &event uses match ergonomics to produce borrowed bindings automatically.
Copyable fields can be bound by value without invalidating their source. A pattern can also move some fields and borrow or copy others, creating a partial move when the aggregate permits it.
The discriminant tells Rust which variant is active. Drop glue destroys only that variant's initialized fields, so inactive variants impose no runtime cleanup.
Internal Model
rustc lowers a match into discriminant tests and control-flow branches. Each arm applies move or borrow operations to the selected field projections, and move analysis merges their initialization states after the match.
Borrowing the scrutinee preserves ownership. Matching by value does not inherently deep-copy payloads; non-Copy bindings transfer them into arm-local places.
Example
rust
enum Event {
Message(String),
Tick,
}
fn main() {
let event = if std::env::args().len() > 1 {
Event::Message(String::from("hello"))
} else {
Event::Tick
};
match &event {
Event::Message(text) => println!("borrowed: {text}"),
Event::Tick => println!("borrowed tick"),
}
match event {
Event::Message(text) => println!("owned: {text}"),
Event::Tick => println!("owned tick"),
}
}Common Mistakes
- Assuming every
match valueexpression necessarily moves every field. - Forgetting that binding a non-
Copypayload by value transfers ownership. - Expecting inactive enum variants to have initialized fields that must be dropped.
Follow-ups
- How do
refandref mutdiffer from matching&Tand&mut T? - When does a pattern create a partial move?
- How does match ergonomics choose a default binding mode?
Related
- Q016. What is a partial move?
- Q017. How does ownership flow through branches, loops, and conditional initialization?
- Q032. How does ownership work for struct fields?
References
- The Rust Programming Language
- Rust Reference