Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The reference pattern in Rust, denoted by the ref and ref mut keywords, is a pattern-matching mechanism used to bind a variable to a reference of a matched value rather than taking ownership (moving) or copying it. It alters the binding mode of the pattern, instructing the compiler to create a borrow (&T or &mut T) pointing to the data being matched.

Syntax and Mechanics

When a pattern matches a value, the default behavior is to bind the variable by value. If the type does not implement the Copy trait, this results in a move. Prefixing the identifier with ref or ref mut overrides this default binding mode.
  • ref creates an immutable reference (&T).
  • ref mut creates a mutable reference (&mut T).
let some_value = String::from("Rust");

// 'ref' binds 'r' as &String, preventing 'some_value' from being moved.
let ref r = some_value; 

// The above is semantically equivalent to:
// let r = &some_value;
In match expressions, reference patterns allow for the structural destructuring of data while simultaneously borrowing its internal fields:
let mut tuple = (String::from("A"), String::from("B"));

match tuple {
    // Binds 'first' as &String and 'second' as &mut String
    (ref first, ref mut second) => {
        // 'first' is an immutable borrow
        // 'second' is a mutable borrow
    }
}

ref vs. & in Patterns

A critical technical distinction in Rust’s pattern syntax is the difference between ref and &. They perform inverse operations during pattern matching:
  • & (Destructuring): Matches against an existing reference and dereferences it. It strips the & away from the type to bind the underlying value.
  • ref (Binding): Matches against a value and creates a reference to it. It adds a & to the resulting variable binding.
let reference: &i32 = &42;

match reference {
    // '&' strips the reference. 'val' takes the underlying i32 by value.
    // This compiles successfully because i32 implements Copy.
    &val => {
        let _x: i32 = val;
    } 
}

let value: String = String::from("Data");

match value {
    // 'ref' creates a reference. 'val' becomes &String.
    // This compiles successfully, leaving 'value' intact.
    ref val => {
        let _x: &String = val;
    } 
}

Interaction with Match Ergonomics and Partial Moves

Modern Rust implements “match ergonomics” (introduced in RFC 2005), which automatically adjusts the default binding mode when matching a reference against a non-reference pattern. If a &T or &mut T is matched against a structural pattern that does not explicitly use &, ref, or ref mut, the compiler implicitly pushes the reference down into the inner bindings. Because of this implicit binding mode adjustment, explicit ref and ref mut patterns are less frequently required than in older editions of Rust. However, they remain mechanically necessary in specific scenarios, most notably for partial moves. A partial move occurs when a pattern moves some fields of an aggregate type by value while simultaneously borrowing other fields by reference within the exact same pattern. This cannot be achieved by simply matching against a reference to the entire owned value.
let tuple = (String::from("Moved"), String::from("Borrowed"));

match tuple {
    // 'moved_val' takes ownership of the first String.
    // 'ref borrowed_val' creates a &String to the second field.
    (moved_val, ref borrowed_val) => {
        // 'tuple' is now partially moved. The first field is consumed,
        // but the second field remains owned by 'tuple' and is only borrowed.
    }
}
Additionally, ref and ref mut are required when explicitly overriding the compiler’s inferred binding mode, such as forcing an immutable borrow of a specific field while matching against a mutable reference.
Master Rust with Deep Grasping Methodology!Learn More