refKeyword
Explanation
ref appears inside a pattern, directly before the identifier being bound:
ref name (and ref mut name for a mutable borrow). It changes the
binding mode of that one identifier from the pattern default — bind by
moving or copying the matched place — to binding by reference instead. It
can appear anywhere an identifier pattern can: a let pattern
(let ref x = value;), a function parameter, or, most commonly, inside a
match arm's destructuring pattern (Variant { ref field } => ...).
Before Rust 2018's "default binding modes" (a.k.a. match ergonomics), ref
was the only way to bind part of a matched value by reference rather than
moving it out. Match ergonomics changed the common case: when the scrutinee
being matched is itself a reference (&value or &mut value), the compiler
now automatically shifts every subsequent binding in the pattern to bind by
reference, so Some(x) matched against a &Option<T> binds x: &T
directly, with no ref written anywhere. This is why ref shows up far
less in modern Rust than it did before 2018 — most code that used to need it
now gets the same effect for free by matching on a reference.
ref is still genuinely needed in two situations match ergonomics doesn't
cover. First: matching directly on an owned value (not a reference) when
you want to borrow only part of it, so the whole value remains usable
afterward — match ergonomics has nothing to activate it if the scrutinee
was never a reference to begin with. Second: fine-grained control inside a
single pattern where different bindings need different modes (for instance,
binding one field mutably while another is left to move or copy normally) —
ergonomics infers one mode top-down from the scrutinee, so an explicit ref
or ref mut is the way to override it for just one binding.
ref is not a modifier on the value being matched (it has no effect on the
type of the scrutinee) and it is not the same token as &: &pattern
matches against a reference (it expects the scrutinee to already be a
reference and "un-borrows" one layer), while ref pattern-binding produces
a reference during the match, regardless of what the scrutinee's type is.
Usage examples
Borrowing a field with `ref` instead of moving it
struct Ticket { code: String }
let ticket = Ticket { code: String::from("A-102") };
let Ticket { ref code } = ticket; // <- `ref` borrows `code` instead of moving it out of `ticket`
println!("{code}");
println!("{}", ticket.code); // still valid: `code` was only borrowed, `ticket` wasn't consumed
Branching on data (pattern matching)
Matching directly on an owned enum (not a reference to one) while still needing to return that same value afterward requires borrowing the field you inspect, rather than letting the match move it out.
enum Shipment {
Pending { tracking_code: String },
Delivered,
}
fn log_tracking(shipment: Shipment) -> Shipment {
match shipment {
Shipment::Pending { ref tracking_code } => {
// <- `ref` borrows `tracking_code` instead of moving it out of `shipment`
println!("still pending: {tracking_code}");
}
Shipment::Delivered => println!("delivered"),
}
shipment // still whole: only `tracking_code` was borrowed during the match, never moved
}
Matching shipment by value would otherwise move
tracking_code out of it the moment that arm's pattern binds, making
shipment only partially usable afterward — the
Rust Reference's binding modes section
documents ref as exactly the tool for keeping a matched-on value intact
when its scrutinee isn't already a reference.
Sharing data with multiple references
Destructuring a struct to read one field while continuing to use the whole struct afterward needs that one field bound by reference, not moved out.
struct Invoice {
number: String,
total_cents: u64,
}
let invoice = Invoice { number: String::from("INV-2048"), total_cents: 4599 };
let Invoice { ref number, .. } = invoice; // <- `ref` borrows `number`, leaving `invoice` itself intact
println!("{number} totals {}", invoice.total_cents); // both `number` and `invoice` are usable here
Without ref, binding number in this pattern would move
the String out of invoice, making invoice.total_cents (and the rest of
invoice) inaccessible afterward — the
Rust Reference
covers ref as the way to keep the source place valid when only one field
needs to be shared out of it.
Mutating through a reference
Mutating one field of an owned enum in place, through a match, needs
ref mut — without it, a Copy field like a counter would bind as a
detached copy, and mutating the copy would silently do nothing to the
original.
enum Task {
Active { retries: u32 },
Done,
}
fn record_retry(mut task: Task) -> Task {
match task {
Task::Active { ref mut retries } => {
// <- `ref mut` mutably borrows the real field; without it, `retries: u32` would just be a copy
*retries += 1;
}
Task::Done => {}
}
task
}
u32 is Copy, so without ref mut the pattern would
bind retries as an independent copy and *retries += 1 would mutate
nothing that survives the match — the
Rust Reference's binding modes section
is explicit that ref mut is required to get a genuine mutable borrow into
the matched place itself.