Jun 28, 2026

Rust’s Ownership System, for the Curious

4 min read

Table of Contents

Personally, what makes Rust so fun and intriguing as a beginner to the language and systems programming, is the way it handles memory management.

This is a short post on Rust's memory management system, and hopefully it'll make you a little more interested in Rust.

Wait, what is Rust for?

Some use-cases for Rust include

  • dev tools
  • operating systems
  • databases/storage engines

It gives you the speed and low-level control of C++, with stronger safety checks around memory.

A Quick Rundown on Ownership

Rust has three fundamental ownership rules, which govern how memory is managed

  1. A value must have an owner
  2. A value must only have one owner
  3. When the owner goes out of scope, its value is dropped

fn main() {
  let p = 1;
  let q = p; // owner is now q
} // q out of scope, value dropped

Single ownership makes the responsibility of freeing memory very clear, since two owners trying to free the same memory allocation is unsafe.

Automatically dropping values after they go out of scope also prevents accidental memory leaks.

Borrowing instead of Owning

References allow callers to borrow data without taking ownership.

Note that a borrow can end at its last use, instead of adhering to lexical scope. Keep this concept in mind when reference scopes are mentioned.

1. Multiple immutable refs can exist for a value

There are no problems doing multiple read-only references.

2. Only one mutable ref can exist for a value in a scope

fn main() {
  let mut a = String::from("hello");

  let b = &mut a;
  let c = &mut a; // compiler throws

  println!("{} {}", b, c);
}

Multiple writes to the same value at the same time can cause data races and aliasing bugs. Thus Rust only allows one mutable reference at a time.

3. Mutable and immutable refs can't exist for the same value in the same scope

fn main() {
  let mut x = String::from("world");

  let y = &x;
  let z = &mut x; // compiler throws
  
  println!("{} {}", y, z);
}

If a value is being read through an immutable ref, Rust prevents that same value from being mutated at the same time.

This avoids aliasing bugs where one part of the code assumes a value is stable, while another part changes it underneath.

4. Refs must always point to valid data

fn main() {
  let r;
  {
    let g = 2;
    r = &g; // compiler throws, since r outlives g
  }

  println!("{}", r);
}

Prevents dangling pointers, as the compiler checks for refs that outlive its owner.

Conclusion

To sum it all up, we went through the basics of memory management in Rust, and we saw how these simple yet opinionated rules can help mitigate common memory bugs!

If you want to learn more about Rust, The Book and Rustlings are a great way to start!