iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Ownership

Ownership is Rust’s killer feature: every value has exactly one owner; when the owner goes out of scope, the value is dropped. No GC, no double-free, no use-after-free — checked at compile time.

Move, copy, drop

EXAMPLE
fn main() {
    // 1) MOVE — heap-owned types transfer ownership on assignment
    let s1 = String::from("hi");
    let s2 = s1;            // s1 is no longer usable
    // println!("{s1}");    // ERROR: borrow of moved value
    println!("{s2}");

    // 2) COPY — small stack types are duplicated, both stay valid
    let a = 5;
    let b = a;
    println!("{a} {b}");    // both fine — i32 implements Copy

    // 3) CLONE — explicit deep copy for non-Copy types
    let s3 = String::from("world");
    let s4 = s3.clone();
    println!("{s3} {s4}");

    // 4) Functions take ownership the same way
    take(s2);
    // println!("{s2}"); // ERROR: s2 was moved into take

    // 5) Return values give ownership BACK
    let s5 = give();
    println!("{s5}");

    // 6) Drop runs deterministically at end of scope
    {
        let temp = String::from("local");
        // temp dropped here automatically
    }
}

fn take(s: String) {
    println!("took {s}");
}

fn give() -> String {
    String::from("made")
}

Why it matters

Once you internalise move-by-default, the borrow-checker errors stop feeling random. Most “cannot borrow as mutable” bugs vanish when you ask “who owns this right now?”

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
let s1 = String::from("hi");
let s2 = s1;          // moved
// println!("{}", s1); // ERROR: s1 moved
println!("{}", s2);
Try it Yourself »

Exercise

Allocate a String on the heap.

let s = ::from("hi");

Test yourself

Q1. Each value has…
Q2. Moving a String value out…
Q3. Types that implement Copy…

Discussion

Loading…