DEV Community

Cover image for Ownership and Borrowing: My Journey Into Rust’s Unique Memory System
Vedant Navale
Vedant Navale

Posted on

Ownership and Borrowing: My Journey Into Rust’s Unique Memory System

So,I’ve been diving into Rust, and one thing that keeps popping up everywhere is this idea of ownership and borrowing.
At first, it felt like Rust was being too strict with me 😅 errors everywhere! But then I realized… these rules are the secret sauce that make Rust memory safe without a garbage collector.

I tried to note down the important rules (12 of them) that I keep in mind while coding, along with examples. Writing them out helps me remember and maybe it’ll help you too if you’re learning like me.

🦀 Rule 1: Every value has exactly one owner
fn main() {
    let s = String::from("hello");
    println!("{}", s); // s owns "hello"
}
Enter fullscreen mode Exit fullscreen mode

The variable s owns the string. Simple start.

🦀 Rule 2: When the owner goes out of scope, the value is dropped
fn main() {
    {
        let s = String::from("hello");
    } // s goes out of scope -> memory freed automatically
}
Enter fullscreen mode Exit fullscreen mode

No free() needed. Rust does it for us.

🦀 Rule 3: Assigning moves ownership
fn main() {
    let s1 = String::from("hello");
    let s2 = s1; // ownership moved
    // println!("{}", s1); // ❌ error: s1 not valid anymore
}
Enter fullscreen mode Exit fullscreen mode

This was one of the first “gotchas” for me. After s1 moves, it’s gone.

🦀 Rule 4: Clone makes a deep copy
fn main() {
    let s1 = String::from("hello");
    let s2 = s1.clone();
    println!("{} and {}", s1, s2); // ✅ both valid
}

Enter fullscreen mode Exit fullscreen mode

So if I really need two separate copies, I clone.

🦀 Rule 5: Primitives are Copy
fn main() {
    let x = 10;
    let y = x; // just copied
    println!("{} and {}", x, y); // ✅ works fine
}
Enter fullscreen mode Exit fullscreen mode

This explains why integers never gave me move errors 😅.

🦀 Rule 6: Borrow with &
fn main() {
    let s = String::from("hello");
    print_length(&s); // borrow, no move
    println!("Still valid: {}", s); // ✅
}

fn print_length(s: &String) {
    println!("Length: {}", s.len());
}
Enter fullscreen mode Exit fullscreen mode

Here, ownership stays with s, but the function can still read it.

🦀 Rule 7: Mutable references need &mut
fn main() {
    let mut s = String::from("hello");
    change(&mut s);
    println!("{}", s); // "hello world"
}

fn change(s: &mut String) {
    s.push_str(" world");
}
Enter fullscreen mode Exit fullscreen mode

The first time I used &mut, it clicked borrowing but with permission to change.

🦀 Rule 8: Only one mutable reference at a time
fn main() {
    let mut s = String::from("hello");
    let r1 = &mut s;
    // let r2 = &mut s; // ❌ not allowed
    println!("{}", r1);
}

Enter fullscreen mode Exit fullscreen mode

Rust says: “No data races allowed here.”

🦀 Rule 9: Multiple immutable references are fine
fn main() {
    let s = String::from("hello");
    let r1 = &s;
    let r2 = &s;
    println!("{} and {}", r1, r2); // ✅ works
}

Enter fullscreen mode Exit fullscreen mode

This makes sense if nobody’s changing it, multiple readers are fine.

🦀 Rule 10: But you can’t mix mutable and immutable references
fn main() {
    let mut s = String::from("hello");
    let r1 = &s;
    let r2 = &s;
    // let r3 = &mut s; // ❌ clash
    println!("{} and {}", r1, r2);
}
Enter fullscreen mode Exit fullscreen mode

Took me a while to accept this. Rust protects me even from myself.

🦀 Rule 11: References must always be valid
fn main() {
    let r;
    {
        let s = String::from("hello");
        r = &s;
    }
    // println!("{}", r); // ❌ dangling reference
}
Enter fullscreen mode Exit fullscreen mode

This is what other languages sometimes allow… but leads to bugs. Rust just stops me.

🦀 Rule 12: These rules together = safety

At first these rules feel like handcuffs. But the more I code, the more I see the benefits:

No null pointers
No dangling references
No data races in multi-threaded code
And all of this checked at compile time.

🎯 My Takeaway
I used to fight with the borrow checker, but now I think of it as a teacher. The compiler forces me to think about ownership. And honestly, that’s making me a better programmer.

I’m still learning, but these 12 rules are like my “cheat sheet” for Rust’s ownership model. Hopefully this helps someone else who’s starting out too 🙌.

Top comments (0)