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");
PascalCase.
Discussion
Loading…