Click any item to expand the explanation and examples.
📝 Basics
Variables and types basics
// Immutable by default let name = "Alice"; let age: i32 = 30;// Mutable let mut count = 0; count += 1;
// Constants const MAX_SIZE: usize = 100;
// Shadowing (re-declare same name) let x = 5; let x = x + 1; // x is now 6 let x = “hello”; // x is now a string (different type!)
// Types // i8, i16, i32, i64, i128, isize // u8, u16, u32, u64, u128, usize // f32, f64 // bool, char // &str (string slice), String (owned string) // () — unit type (like void)
// Type conversion let x: i32 = 42; let y: f64 = x as f64;
Functions basics
fn greet(name: &str) -> String {
format!("Hello, {}!", name)
}
// Last expression is the return value (no semicolon)
fn add(a: i32, b: i32) -> i32 {
a + b
}
// No return value
fn log(msg: &str) {
println!(”{}”, msg);
}
// Closures
let double = |x: i32| x * 2;
let result = double(5); // 10
// Closure capturing environment
let offset = 10;
let add_offset = |x| x + offset;
🔑 Ownership & Borrowing
Ownership rules ownership
// Rule 1: Each value has one owner
let s1 = String::from("hello");
let s2 = s1; // s1 is MOVED to s2
// println!("{}", s1); // ❌ Error! s1 is no longer valid
// Rule 2: Clone to copy heap data
let s1 = String::from(“hello”);
let s2 = s1.clone(); // Deep copy
println!(”{} {}”, s1, s2); // ✅ Both valid
// Rule 3: Stack types (i32, bool, f64, char) are copied automatically
let x = 5;
let y = x; // Copy, not move
println!(”{} {}”, x, y); // ✅ Both valid
// Ownership and functions
fn take_ownership(s: String) {
println!(”{}”, s);
} // s is dropped here
let s = String::from(“hello”);
take_ownership(s);
// println!(”{}”, s); // ❌ s was moved into the function
Borrowing — & and &mut ownership
// Immutable borrow (can have many)
fn print_len(s: &String) {
println!("Length: {}", s.len());
}
let s = String::from(“hello”);
print_len(&s); // Borrow
println!(”{}”, s); // ✅ Still valid
// Mutable borrow (can have only ONE at a time)
fn add_world(s: &mut String) {
s.push_str(”, world!”);
}
let mut s = String::from(“hello”);
add_world(&mut s);
println!(”{}”, s); // “hello, world!”
// Rules:
// - Many &T OR one &mut T (never both)
// - References must always be valid (no dangling pointers)
📦 Structs & Enums
Structs data
struct User {
name: String,
email: String,
age: u32,
}
// Create
let user = User {
name: String::from(“Alice”),
email: String::from(“alice@example.com”),
age: 30,
};
// Access
println!(”{}”, user.name);
// Methods
impl User {
// Constructor (convention: fn new)
fn new(name: &str, email: &str) -> Self {
User {
name: name.to_string(),
email: email.to_string(),
age: 0,
}
}
// Method (takes &self)
fn greeting(&self) -> String {
format!("Hi, I'm {}", self.name)
}
// Mutable method
fn set_age(&mut self, age: u32) {
self.age = age;
}
}
let mut user = User::new(“Alice”, “alice@example.com”);
user.set_age(30);
Enums and pattern matching data
enum Color {
Red,
Green,
Blue,
Custom(u8, u8, u8), // With data
}
let c = Color::Custom(255, 128, 0);
// Pattern matching (must be exhaustive)
match c {
Color::Red => println!(“Red”),
Color::Green => println!(“Green”),
Color::Blue => println!(“Blue”),
Color::Custom(r, g, b) => println!(“RGB({},{},{})”, r, g, b),
}
// if let (match one pattern)
if let Color::Custom(r, _, _) = c {
println!(“Red component: {}”, r);
}
// Option — Rust’s null replacement
let x: Option<i32> = Some(42);
let y: Option<i32> = None;
match x {
Some(val) => println!(“Got {}”, val),
None => println!(“Nothing”),
}
// Unwrap shortcuts
x.unwrap() // Panics if None
x.unwrap_or(0) // Default value
x.unwrap_or_default() // Type’s default
⚠️ Error Handling
Result and the ? operator errors
use std::fs; use std::io;// Functions return Result<T, E> fn read_file(path: &str) -> Result<String, io::Error> { fs::read_to_string(path) }
// Handle with match match read_file(“config.txt”) { Ok(content) => println!(”{}”, content), Err(e) => eprintln!(“Error: {}”, e), }
// The ? operator — propagate errors fn read_config() -> Result<String, io::Error> { let content = fs::read_to_string(“config.txt”)?; // Returns Err early if fails Ok(content.trim().to_string()) }
// Custom error #[derive(Debug)] enum AppError { Io(io::Error), Parse(String), }
impl From<io::Error> for AppError { fn from(e: io::Error) -> Self { AppError::Io(e) } }
// Or use anyhow crate for simple error handling // use anyhow::{Result, Context}; // fn main() -> Result<()> { // let f = fs::read_to_string(“file.txt”) // .context(“Failed to read config”)?; // Ok(()) // }
🔌 Traits
Traits — Rust's interfaces traits
trait Summary {
fn summarize(&self) -> String;
// Default implementation
fn preview(&self) -> String {
format!("{}...", &self.summarize()[..20])
}
}
struct Article {
title: String,
content: String,
}
impl Summary for Article {
fn summarize(&self) -> String {
format!(”{}: {}”, self.title, &self.content[..50])
}
}
// Trait as parameter
fn notify(item: &impl Summary) {
println!(“Breaking: {}”, item.summarize());
}
// Trait bound syntax (equivalent)
fn notify<T: Summary>(item: &T) {
println!(“Breaking: {}”, item.summarize());
}
// Common derive traits
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct Point {
x: i32,
y: i32,
}
📋 Collections
Vec, HashMap, iterators collections
// Vec let mut v = vec![1, 2, 3]; v.push(4); v.pop(); v.len(); v[0]; // Panics if out of bounds v.get(0); // Returns Option// HashMap use std::collections::HashMap; let mut map = HashMap::new(); map.insert(“key”, “value”); map.get(“key”); // Returns Option map.contains_key(“key”); map.remove(“key”);
// Iterators (Rust’s superpower) let nums = vec![1, 2, 3, 4, 5];
let doubled: Vec<i32> = nums.iter().map(|x| x * 2).collect(); let evens: Vec<&i32> = nums.iter().filter(|x| *x % 2 == 0).collect(); let sum: i32 = nums.iter().sum(); let any_big = nums.iter().any(|x| *x > 3); let all_pos = nums.iter().all(|x| *x > 0); let found = nums.iter().find(|x| **x == 3);
// Chain let result: Vec<i32> = nums.iter() .filter(|x| **x > 2) .map(|x| x * 10) .collect();
🔧 Cargo Commands
cargo — project management cli
# Create project cargo new my-project cargo new my-lib --libBuild and run
cargo build cargo build —release cargo run cargo run —release
Test
cargo test cargo test test_name cargo test — —nocapture # Show println output
Check (fast compile check, no binary)
cargo check
Format and lint
cargo fmt cargo clippy
Add dependency
cargo add serde cargo add tokio —features full
Update dependencies
cargo update
Documentation
cargo doc —open