A language tour
Memory safety without a garbage collector. Speed without undefined behaviour. The compiler as your partner.
01 β Ownership
Rust's ownership system is its defining idea. Every piece of data has exactly one owner. When the owner goes out of scope, the data is freed. No garbage collector, no double-free, no use-after-free β guaranteed by the compiler.
"Rust gives you the choice between a safe, idiomatic form and a fast, machine-close form. You shouldn't need to choose one and sacrifice the other."
β The Rust Bookfn main() { let s1 = String::from("hello"); // Move: s1 is no longer valid β ownership transferred to s2 let s2 = s1; // println!("{}", s1); β compile error: value moved println!("{}", s2); // s2 is valid // Clone: explicit deep copy when you need two owners let s3 = s2.clone(); println!("{} and {}", s2, s3); // both valid // s2 and s3 are freed here β automatically, deterministically } // Copy types (i32, bool, f64) are cloned implicitly β they're cheap
Move semantics are not a performance optimisation in Rust β they're the mechanism that guarantees memory safety. The compiler tracks every value's owner at compile time, with zero runtime overhead.
02 β Borrowing
Borrowing lets you use a value without taking ownership. The borrow checker enforces one rule: you can have many shared references, or one exclusive reference β never both at the same time. This eliminates data races at compile time.
fn length(s: &String) -> usize { s.len() // borrows s, does not take ownership } fn first_word(s: &str) -> &str { let bytes = s.as_bytes(); for (i, &byte) in bytes.iter().enumerate() { if byte == b' ' { return &s[..i]; } } &s[..] } fn main() { let mut s = String::from("hello world"); let word = first_word(&s); // immutable borrow // s.clear(); β compile error: can't mutate while borrowed println!("first word: {word}"); }
The borrow checker ensures that word (a slice into s) cannot outlive s, and that s cannot be modified while word exists. Iterator invalidation bugs are impossible by construction.
03 β Result & Option
Rust has no null and no exceptions. Option<T> replaces null; Result<T, E> replaces exceptions. The compiler forces you to handle both cases. The ? operator propagates errors ergonomically without hiding them.
use std::{fs, io}; fn read_username(path: &str) -> Result<String, io::Error> { let content = fs::read_to_string(path)?; // ? propagates error let name = content.lines().next() .map(str::to_string) .ok_or(io::Error::other("empty file"))?; Ok(name) } fn main() { match read_username("user.txt") { Ok(name) => println!("Hello, {name}!"), Err(e) => eprintln!("Error: {e}"), } }
The ? operator desugars to: if this is Err, return that error from the current function; otherwise, unwrap the Ok value. It's monadic error propagation with no boilerplate.
04 β Traits
Traits define shared behaviour without inheritance. Implement a trait for any type β even types you don't own. Combined with monomorphisation, trait dispatch compiles to direct function calls, not virtual dispatch.
trait Area { fn area(&self) -> f64; } struct Circle { radius: f64 } struct Rectangle { w: f64, h: f64 } impl Area for Circle { fn area(&self) -> f64 { std::f64::consts::PI * self.radius.powi(2) } } impl Area for Rectangle { fn area(&self) -> f64 { self.w * self.h } } // Generic function β monomorphised at compile time, zero overhead fn print_area<T: Area>(shape: &T) { println!("Area: {:.2}", shape.area()); } fn main() { print_area(&Circle { radius: 5.0 }); // 78.54 print_area(&Rectangle { w: 3.0, h: 4.0 }); // 12.00 }
The compiler generates two versions of print_area β one for Circle, one for Rectangle. Each is a direct function call. No vtable, no pointer indirection, no cache miss.
05 β Fearless Concurrency
The same ownership rules that prevent memory errors also prevent data races. If you can share data between threads, it's because the type system guarantees it's safe to do so. Rust threads don't just run fast β they run correctly.
use std::{sync::{Arc, Mutex}, thread}; fn main() { // Arc = atomically reference counted (shared ownership across threads) // Mutex = mutual exclusion β only one thread writes at a time let counter = Arc::new(Mutex::new(0)); let mut handles = vec![]; for _ in 0..10 { let c = Arc::clone(&counter); let h = thread::spawn(move || { let mut n = c.lock().unwrap(); *n += 1; }); handles.push(h); } for h in handles { h.join().unwrap(); } println!("{}", counter.lock().unwrap()); // always 10 }
You can't share &mut T between threads unless T: Send + Sync. The compiler verifies these traits at every thread boundary. Writing a data race is a compile error, not a runtime mystery.
06 β The Whole Picture
Stack Overflow's developer survey named Rust the most loved language nine years in a row. Developers who use it don't want to stop.
Rust is now an officially supported language for Linux kernel development β the first new language accepted in decades.
Rust is the premier language for WebAssembly. wasm-pack makes it trivial to compile Rust to run in the browser.
Rust's package manager is widely considered the best in any language. Build, test, publish, document β all from one tool.
Rust's async model is zero-cost β futures compile to state machines with no heap allocation or runtime overhead.
Safe Rust has no undefined behaviour. The entire class of UB exploits that plague C and C++ simply do not exist.