Cheatsheets / Rust

Rust Cheatsheet

Complete Rust reference. Hit Ctrl+P to print.

Variables & Types

let x = 5;Immutable binding — cannot reassign
let mut x = 5;Mutable binding — can reassign
const MAX: u32 = 100;Constant — must have type annotation, evaluated at compile time
static GREETING: &str = "hello";Static — lives for entire program duration
let x: i32 = 42;Explicit type annotation
i8 / i16 / i32 / i64 / i128 / isizeSigned integers
u8 / u16 / u32 / u64 / u128 / usizeUnsigned integers (usize used for indexing)
f32 / f64Floating point (f64 is default)
booltrue or false
charUnicode scalar value — single quotes: 'A'
(i32, &str)Tuple type
let tup = (1, "hi"); tup.0 / tup.1Tuple access by index
let (a, b) = tup;Destructure tuple
[i32; 5]Fixed-size array type
let arr = [1, 2, 3, 4, 5]; arr[0]Array literal and index access
let arr = [0; 5];Array of 5 zeros
let x = { let y = 3; y + 1 };Block expression — evaluates to last expression (no semicolon)

Strings

&strString slice — immutable reference to UTF-8 data, usually in binary
StringOwned, heap-allocated, growable UTF-8 string
"hello"String literal — type is &str
String::from("hello")Create owned String from literal
"hello".to_string()Convert &str to String
s.as_str() / &sBorrow a String as &str
s.len()Byte length
s.is_empty()True if length is 0
s.contains("sub")True if substring found
s.starts_with("pre") / s.ends_with("suf")Check prefix / suffix
s.find("sub")Return Option byte index of first match
s.replace("a", "b")Replace all occurrences — returns new String
s.to_uppercase() / s.to_lowercase()Change case — returns new String
s.trim() / s.trim_start() / s.trim_end()Strip whitespace — returns &str slice
s.split(",").collect::<Vec<_>>()Split on delimiter, collect into Vec
s.chars().count()Number of Unicode scalar values
s.chars().nth(2)Nth character as Option
s1 + &s2Concatenate — moves s1, borrows s2
format!("{} {}", a, b)Format macro — returns owned String
42.to_string()Convert number to String
"42".parse::<i32>()Parse string to typed value — returns Result

Collections

let v: Vec<i32> = Vec::new();Create empty Vec
let v = vec![1, 2, 3];Vec literal via macro
v.push(4)Append element
v.pop()Remove and return last element as Option
v.len() / v.is_empty()Length / empty check
v[0] / v.get(0)Index access (panics if OOB) / safe access returning Option
v.iter()Iterate by reference (&T)
v.iter_mut()Iterate by mutable reference (&mut T)
v.into_iter()Consuming iterator — takes ownership (T)
v.iter().map(|x| x * 2).collect::<Vec<_>>()Transform and collect
v.iter().filter(|x| **x > 2).collect::<Vec<_>>()Filter and collect
v.iter().fold(0, |acc, x| acc + x)Fold to single value
v.iter().sum::<i32>() / v.iter().product::<i32>()Sum / product
v.iter().any(|x| *x > 3) / v.iter().all(|x| *x > 0)Any / all match predicate
v.sort() / v.sort_by(|a, b| a.cmp(b))Sort in place / with comparator
v.dedup()Remove consecutive duplicates (sort first for full dedup)
v.retain(|x| *x > 0)Keep only elements matching predicate
use std::collections::HashMap;Import HashMap
let mut m = HashMap::new();Create empty HashMap
m.insert("key", 1);Insert key-value pair
m.get("key")Returns Option<&V>
m.contains_key("key")True if key exists
m.remove("key")Remove key, returns Option
m.entry("key").or_insert(0)Get or insert default value
use std::collections::HashSet;Import HashSet

Control Flow

if x > 0 { } else if x < 0 { } else { }if/else — no parentheses; braces required
let y = if x > 0 { 1 } else { -1 };if as expression — both arms must return same type
loop { ... break value; }Infinite loop — can return a value via break
while x > 0 { }Loop while condition is true
for x in collection { }For loop — takes ownership or borrows depending on iterator
for x in &v { }Iterate by reference
for (i, x) in v.iter().enumerate() { }Iterate with index
for x in 0..10 { } / 0..=10Exclusive range / inclusive range
break / continueExit loop / skip to next iteration
match x { 1 => "one", 2 | 3 => "two or three", 4..=9 => "four to nine", _ => "other", }match — exhaustive, no fallthrough
match x { Some(v) => v, None => 0 }match on enum variants
if let Some(v) = opt { }if let — match one pattern, ignore rest
while let Some(v) = iter.next() { }while let — loop while pattern matches
let Some(v) = opt else { return; };let-else — bind or run diverging else block (Rust 1.65+)

Functions

fn add(a: i32, b: i32) -> i32 { a + b }Function — last expression without semicolon is the return value
fn greet() { }Function returning unit ()
fn never() -> ! { panic!("!") }! — never type, function never returns
return value;Explicit early return
|x| x * 2Closure — captures environment
|x: i32| -> i32 { x * 2 }Closure with explicit types
move |x| x + offsetmove closure — takes ownership of captured variables
fn apply(f: impl Fn(i32) -> i32, x: i32) -> i32Accept closure as argument with impl Trait
fn apply<F: Fn(i32) -> i32>(f: F, x: i32) -> i32Same with generic bound
fn make_adder(x: i32) -> impl Fn(i32) -> i32 { move |y| x + y }Return a closure
fn largest<T: PartialOrd>(list: &[T]) -> &TGeneric function with trait bound
fn first<T>(list: &[T]) -> Option<&T> { list.get(0) }Return reference with lifetime tied to input

Structs & Enums

struct Point { x: f64, y: f64 }Named-field struct
struct Pair(i32, i32);Tuple struct
struct Marker;Unit struct — no fields
let p = Point { x: 1.0, y: 2.0 };Struct literal
let p2 = Point { x: 3.0, ..p };Struct update — copy remaining fields from p
p.x / p.yField access
let Point { x, y } = p;Destructure struct
impl Point { fn distance(&self) -> f64 { } }impl block — attach methods to struct
fn new(x: f64, y: f64) -> Self { Point { x, y } }Associated function (constructor convention)
&self / &mut self / selfImmutable borrow / mutable borrow / take ownership
#[derive(Debug, Clone, PartialEq)]Derive common traits automatically
enum Direction { North, South, East, West }Simple enum
enum Shape { Circle(f64), Rect(f64, f64) }Enum with data
enum Message { Quit, Move { x: i32, y: i32 }, Write(String) }Enum with varied data per variant
Option<T>Built-in enum: Some(T) or None — no null in Rust
Result<T, E>Built-in enum: Ok(T) or Err(E) — for fallible operations

Ownership & Borrowing

let s1 = String::from("hi"); let s2 = s1;Move — s1 is no longer valid; heap data transferred to s2
let s2 = s1.clone();Deep copy — both s1 and s2 are valid
let x = 5; let y = x;Copy — primitives implement Copy, no move
fn take(s: String) { } // s dropped herePassing to function moves ownership
fn borrow(s: &String) { }Shared reference — borrow without taking ownership
fn mutate(s: &mut String) { }Mutable reference — exclusive, no other borrows active
&TShared reference — many readers, no writers
&mut TExclusive reference — one writer, no readers
fn longest<'a>(x: &'a str, y: &'a str) -> &'a strLifetime annotation — output lives as long as shorter of x, y
struct Excerpt<'a> { text: &'a str }Struct holding a reference needs lifetime parameter
Box<T>Heap-allocated value — single owner
Rc<T>Reference-counted pointer — multiple owners, single thread
Arc<T>Atomic reference-counted pointer — multiple owners, thread-safe
RefCell<T>Interior mutability — borrow rules checked at runtime
Rc<RefCell<T>>Common pattern for shared mutable state in single-threaded code

Error Handling

Result<T, E>Ok(T) on success, Err(E) on failure
Option<T>Some(T) if present, None if absent
result?? operator — return Err early if Err, unwrap if Ok
opt?? operator on Option — return None early if None
result.unwrap()Get Ok value — panics if Err
result.expect("msg")Like unwrap but panics with a custom message
result.unwrap_or(0)Get Ok value or default
result.unwrap_or_else(|e| handle(e))Get Ok value or compute default from error
result.is_ok() / result.is_err()Check result variant without consuming
result.map(|v| v * 2)Transform Ok value, pass Err through
result.map_err(|e| MyError(e))Transform Err value, pass Ok through
result.and_then(|v| fallible(v))Chain fallible operations — flatMap
opt.unwrap_or_default()Get Some value or type default
opt.map(|v| v * 2)Transform Some value, pass None through
opt.ok_or(MyError)Convert Option to Result
#[derive(Debug)]\nenum AppError { NotFound, ParseFailed(String) }Custom error enum
impl std::error::Error for AppError {}Implement the Error trait for compatibility
panic!("unexpected state")Unrecoverable error — unwinds stack

Traits

trait Summary { fn summarise(&self) -> String; }Define a trait
trait Greet { fn greet(&self) -> String { String::from("Hello") } }Trait with default method implementation
impl Summary for Article { fn summarise(&self) -> String { ... } }Implement a trait for a type
fn notify(item: &impl Summary)impl Trait in parameter position
fn notify<T: Summary>(item: &T)Generic with trait bound — same as above
fn notify<T: Summary + Display>(item: &T)Multiple trait bounds
fn notify<T>(item: &T) where T: Summary + Displaywhere clause — cleaner for complex bounds
fn returns_summary() -> impl SummaryReturn a type that implements a trait
Box<dyn Summary>Trait object — dynamic dispatch, heap-allocated
Display / Debug / Clone / Copy / PartialEq / Eq / Hash / OrdCommon standard library traits
From<T> / Into<T>Infallible conversion — impl From, get Into for free
TryFrom<T> / TryInto<T>Fallible conversion — returns Result
Iterator — fn next(&mut self) -> Option<Self::Item>Core iterator trait — implement next, get map/filter/etc for free
impl Iterator for Counter { type Item = u32; ... }Custom iterator with associated type