In this lesson, you will learn how reference semantics behave differently when your data resides on the stack versus the heap.
Understanding the Two Memory Regions
In Rust, the stack is where we store data with a known, fixed size at compile time, like integers or small structs. It is incredibly fast because the CPU just moves a pointer up or down. The heap, by contrast, is a large, flexible area of memory where you store data that might grow or change size at runtime, like a String or a Vec<T>.
When you create a reference to data, the compiler handles the "address" of that data. However, the nature of that address changes depending on where the data lives.
Stack vs. Heap References
When you borrow data from the stack, you are pointing to a location within the current function's local frame. Because this memory is cleared automatically when the function ends, the borrow checker is very strict about ensuring your reference never outlives the function scope.
When you borrow data from the heap, the reference points to a memory address that persists independently of the variable that owns the heap-allocated object. Consider this example:
fn main() {
let stack_val = 42; // Lives on the stack
let heap_val = String::from("Hi"); // "Hi" is on the heap
let stack_ref = &stack_val; // Points to the stack
let heap_ref = &heap_val; // Points to the heap-allocated memory
}
Even though both stack_ref and heap_ref look identical syntactically, they have different "lives." If you move a String (which owns heap data), the pointer, length, and capacity are moved, but the heap data itself stays where it is. If you move a stack variable, the actual bits of the value are copied to a new stack location.
Because references are just "pointers to memory," they don't care where the memory lives—but the Borrow Checker cares deeply. It tracks the lifetime of the stack frame for stack data, and the ownership of the heap-allocated container for heap data. Whether the memory is fast (stack) or flexible (heap), the safety rules remain constant: you cannot have a dangling reference to either.
Key Takeaway: While references look identical regardless of where data resides, the compiler enforces safety by tracking stack frame lifetimes for local data and owner lifetimes for heap-allocated data.