Rust Course

Rust Ownership, Borrowing, and Lifetimes

A self-study guide for Python 3 compiled from the materials on this site. Primarily intended for those who want to learn the Python programming language from scratch.

The Ownership Rules

Ownership is Rust's most unique feature and enables memory safety without a garbage collector. Three rules govern ownership:

  • Each value has exactly one owner (a variable)
  • When the owner goes out of scope, the value is dropped (freed)
  • There can only be one owner at a time
fn main() {
    let s1 = String::from("hello");
    let s2 = s1;          // s1 is MOVED to s2
    // println!("{}", s1); // ❌ s1 no longer valid!
    println!("{}", s2);   // ✅ "hello"
}

Clone — deep copy

let s1 = String::from("hello");
let s2 = s1.clone();       // explicit deep copy
println!("{} and {}", s1, s2); // both valid

Borrowing with References

References allow you to refer to a value without taking ownership:

fn calculate_length(s: &String) -> usize {
    s.len() // borrow only, no ownership transfer
}

let s1 = String::from("hello");
let len = calculate_length(&s1); // pass reference
println!("Length of '{}' is {}", s1, len); // s1 still valid

Mutable References

fn change(s: &mut String) {
    s.push_str(", world");
}

let mut s = String::from("hello");
change(&mut s);
println!("{}", s); // "hello, world"

// Rules: only ONE mutable reference at a time
// and no mutable + immutable refs simultaneously

Slices

let s = String::from("hello world");
let hello = &s[0..5];   // slice: "hello"
let world = &s[6..11];  // slice: "world"
println!("{} {}", hello, world);

// Array slices
let arr = [1, 2, 3, 4, 5];
let slice = &arr[1..3]; // [2, 3]
println!("{:?}", slice);