Rust Cheat Sheet
A comprehensive quick reference for the Rust programming language. Covers variables, ownership, borrowing, traits, error handling, iterators, concurrency, and more.
Variables & Constants
| Pattern | Description | Example |
|---|---|---|
let |
Immutable variable binding (default) | let x = 5; |
let mut |
Mutable variable binding | let mut x = 5; x = 10; |
const |
Compile-time constant (must annotate type) | const MAX_SIZE: u32 = 1000; |
static |
Static lifetime variable (global) | static VERSION: &str = "1.0"; |
static mut |
Mutable static (requires unsafe) |
static mut COUNT: u32 = 0; |
| Shadowing | Re-declare a variable with the same name | let x = 5; let x = x + 1; let x = "now a string"; |
| Type annotation | Explicitly specify the type | let x: i32 = 42; |
| Destructuring | Bind multiple variables at once | let (x, y, z) = (1, 2.0, "three"); |
Data Types
| Type | Description | Example |
|---|---|---|
i8, i16, i32, i64, i128 |
Signed integers (8 to 128 bit) | let x: i32 = -42; |
u8, u16, u32, u64, u128 |
Unsigned integers (8 to 128 bit) | let x: u8 = 255; |
isize, usize |
Platform-dependent size (pointer width) | let idx: usize = 0; |
f32, f64 |
Floating-point numbers (32 and 64 bit) | let pi: f64 = 3.14159; |
bool |
Boolean (true or false) |
let active: bool = true; |
char |
Unicode scalar value (4 bytes) | let c: char = 'R'; |
String |
Heap-allocated, growable UTF-8 string | let s = String::from("hello"); |
&str |
String slice (borrowed reference to string data) | let s: &str = "hello"; |
| Tuple | Fixed-size collection of mixed types | let t: (i32, f64, &str) = (1, 2.0, "hi"); |
| Array | Fixed-size collection of same type | let a: [i32; 5] = [1, 2, 3, 4, 5]; |
| Slice | Reference to a contiguous sequence | let slice: &[i32] = &a[1..3]; |
| Unit type | Empty tuple, like void | let unit: () = (); |
Control Flow
| Construct | Description | Example |
|---|---|---|
if / else |
Conditional branching (no parens needed) | if x > 5 { "big" } else { "small" } |
if let |
Pattern match in conditional | if let Some(v) = opt { println!("{v}"); } |
loop |
Infinite loop (break to exit) | loop { break; } |
loop with value |
Return a value from a loop via break | let x = loop { break 42; }; |
while |
Conditional loop | while x < 10 { x += 1; } |
while let |
Loop while pattern matches | while let Some(v) = stack.pop() { ... } |
for |
Iterate over a range or iterator | for i in 0..10 { println!("{i}"); } |
for (inclusive) |
Inclusive range with ..= |
for i in 0..=10 { /* 0 to 10 */ } |
match |
Exhaustive pattern matching | match x { 1 => "one", 2 => "two", _ => "other" } |
| Loop labels | Named loops for nested break/continue | 'outer: loop { break 'outer; } |
Functions & Closures
| Pattern | Description | Example |
|---|---|---|
| Function | Declare with fn, specify param and return types |
fn add(a: i32, b: i32) -> i32 { a + b } |
| Implicit return | Last expression without ; is the return value |
fn double(x: i32) -> i32 { x * 2 } |
| Early return | Explicit return keyword |
fn check(x: i32) -> bool { if x < 0 { return false; } true } |
| No return value | Returns unit () implicitly |
fn greet(name: &str) { println!("Hi {name}"); } |
| Closure | Anonymous function that captures environment | let add = |a, b| a + b; |
| Typed closure | Closure with explicit type annotations | let add = |a: i32, b: i32| -> i32 { a + b }; |
move closure |
Force closure to take ownership of captured variables | let s = String::from("hi"); let f = move || println!("{s}"); |
| Fn traits | Fn, FnMut, FnOnce -- how closures capture |
fn apply(f: impl Fn(i32) -> i32, x: i32) -> i32 { f(x) } |
| Function pointer | Pass a named function as a value | fn square(x: i32) -> i32 { x * x } |
Ownership & Borrowing
| Concept | Description | Example |
|---|---|---|
| Ownership | Each value has exactly one owner | let s1 = String::from("hi"); let s2 = s1; // s1 is moved |
| Move | Assignment transfers ownership (heap types) | let v1 = vec![1, 2]; let v2 = v1; // v1 invalid |
| Clone | Deep copy to avoid move | let v1 = vec![1, 2]; let v2 = v1.clone(); // both valid |
| Copy | Stack types implement Copy (auto-duplicated) | let x = 5; let y = x; // both valid (i32 is Copy) |
| Immutable borrow | Multiple &T references allowed simultaneously |
let s = String::from("hi"); let r1 = &s; let r2 = &s; |
| Mutable borrow | Only one &mut T at a time, no other refs |
let mut s = String::from("hi"); let r = &mut s; |
| Lifetime annotation | Explicit lifetime to link reference lifetimes | fn longest<'a>(a: &'a str, b: &'a str) -> &'a str { ... } |
'static lifetime |
Reference valid for entire program duration | let s: &'static str = "lives forever"; |
| Lifetime elision | Compiler infers lifetimes in common patterns | fn first(s: &str) -> &str { &s[..1] } // lifetime inferred |
Structs, Enums & Traits
| Pattern | Description | Example |
|---|---|---|
| Struct | Named fields | struct Point { x: f64, y: f64 } |
| Tuple struct | Unnamed fields (newtype pattern) | struct Meters(f64); |
| Unit struct | No fields (marker type) | struct Marker; |
impl block |
Methods and associated functions | impl Point { fn new(x: f64, y: f64) -> Self { Self { x, y } } } |
&self method |
Borrows self immutably | fn distance(&self) -> f64 { (self.x.powi(2) + self.y.powi(2)).sqrt() } |
&mut self method |
Borrows self mutably | fn translate(&mut self, dx: f64) { self.x += dx; } |
| Enum | Type with multiple variants | enum Color { Red, Green, Blue } |
| Enum with data | Variants can hold data | enum Shape { Circle(f64), Rect { w: f64, h: f64 } } |
| Trait | Define shared behavior (like interfaces) | trait Greet { fn hello(&self) -> String; } |
impl Trait for |
Implement a trait for a type | impl Greet for Point { fn hello(&self) -> String { format!("({}, {})", self.x, self.y) } } |
| Default methods | Traits can provide default implementations | trait Greet { fn hello(&self) -> String { "Hi!".into() } } |
| Derive macros | Auto-implement common traits | #[derive(Debug, Clone, PartialEq)] |
impl Trait (arg) |
Accept any type implementing a trait | fn print_it(item: &impl Display) { println!("{item}"); } |
| Trait bounds | Generic constraint with trait | fn print_it<T: Display + Debug>(item: &T) { ... } |
where clause |
Cleaner trait bounds syntax | fn process<T>(item: T) where T: Display + Clone { ... } |
dyn Trait |
Trait object for dynamic dispatch | fn log(writer: &dyn Write) { ... } |
Option & Result
| Type / Method | Description | Example |
|---|---|---|
Option<T> |
Some(T) or None -- nullable values |
let x: Option<i32> = Some(42); |
Result<T, E> |
Ok(T) or Err(E) -- recoverable errors |
let r: Result<i32, String> = Ok(42); |
.unwrap() |
Get value or panic if None/Err | let v = some_option.unwrap(); |
.expect("msg") |
Like unwrap but with custom panic message | let v = some_result.expect("failed to read"); |
.unwrap_or(default) |
Get value or use a default | let v = opt.unwrap_or(0); |
.unwrap_or_else(f) |
Get value or compute default from closure | let v = opt.unwrap_or_else(|| compute_default()); |
.is_some() / .is_none() |
Check if Option contains a value | if opt.is_some() { ... } |
.is_ok() / .is_err() |
Check if Result is success or error | if result.is_ok() { ... } |
.map(f) |
Transform the inner value | let doubled = Some(5).map(|x| x * 2); // Some(10) |
.and_then(f) |
Chain operations that return Option/Result | let r = opt.and_then(|x| if x > 0 { Some(x) } else { None }); |
.ok() |
Convert Result to Option (discards error) | let opt: Option<i32> = result.ok(); |
.transpose() |
Swap Option and Result nesting | let x: Result<Option<i32>, E> = Some(Ok(5)).transpose(); |
Error Handling
| Pattern | Description | Example |
|---|---|---|
? operator |
Propagate error early (returns Err to caller) | let content = std::fs::read_to_string("file.txt")?; |
? with Option |
Also works with Option (returns None) | fn first_char(s: &str) -> Option<char> { s.chars().next() } |
| Custom error type | Define your own error enum | #[derive(Debug)] |
impl Display |
Human-readable error message | impl fmt::Display for AppError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ... } } |
impl From |
Auto-convert errors for ? |
impl From<std::io::Error> for AppError { fn from(e: std::io::Error) -> Self { AppError::Io(e) } } |
Box<dyn Error> |
Quick and flexible error type | fn run() -> Result<(), Box<dyn std::error::Error>> { ... } |
panic!() |
Unrecoverable error -- crashes the thread | panic!("something went terribly wrong"); |
unreachable!() |
Mark code that should never be reached | _ => unreachable!("invalid state") |
todo!() |
Placeholder for unfinished code | fn not_yet() -> i32 { todo!() } |
Collections
| Collection | Description | Example |
|---|---|---|
Vec<T> |
Growable array (most common collection) | let mut v = vec![1, 2, 3]; |
Vec::new() |
Create empty Vec | let mut v: Vec<i32> = Vec::new(); |
Vec::with_capacity(n) |
Pre-allocate capacity | let mut v = Vec::with_capacity(100); |
HashMap<K, V> |
Key-value hash map | use std::collections::HashMap; |
.entry().or_insert() |
Insert if key missing | m.entry("key").or_insert(0); |
HashSet<T> |
Unique value set (fast lookup) | use std::collections::HashSet; |
BTreeMap<K, V> |
Sorted key-value map (by key order) | use std::collections::BTreeMap; |
BTreeSet<T> |
Sorted unique value set | use std::collections::BTreeSet; |
VecDeque<T> |
Double-ended queue | use std::collections::VecDeque; |
LinkedList<T> |
Doubly-linked list (rarely needed) | use std::collections::LinkedList; |
String Handling
| Operation | Description | Example |
|---|---|---|
String vs &str |
Owned (heap) vs borrowed (reference) string | let owned = String::from("hi"); let borrowed: &str = "hi"; |
.to_string() |
Convert &str to String | let s: String = "hello".to_string(); |
.as_str() |
Borrow String as &str | let s = String::from("hi"); let r: &str = s.as_str(); |
format!() |
Build String from format template | let s = format!("{} is {} years old", name, age); |
| Concatenation | Use + or format!() |
let s = s1 + " " + &s2; // s1 is moved |
.push_str() |
Append a string slice | let mut s = String::from("hello"); s.push_str(" world"); |
.push() |
Append a single character | s.push('!'); |
.contains() |
Check if string contains substring | "hello world".contains("world") // true |
.replace() |
Replace occurrences | "hello".replace("l", "r") // "herro" |
.split() |
Split into iterator | "a,b,c".split(',').collect::<Vec<&str>>() |
.trim() |
Remove leading/trailing whitespace | " hello ".trim() // "hello" |
.len() |
Byte length (not char count) | "hello".len() // 5 |
.chars().count() |
Actual character count | "cafe\u{0301}".chars().count() // 5 |
.parse() |
Parse string into another type | let n: i32 = "42".parse().unwrap(); |
Iterators & Combinators
| Method | Description | Example |
|---|---|---|
.iter() |
Iterate by reference (&T) |
for val in vec.iter() { ... } |
.iter_mut() |
Iterate by mutable reference (&mut T) |
for val in vec.iter_mut() { *val += 1; } |
.into_iter() |
Iterate by value (consumes collection) | for val in vec.into_iter() { ... } |
.map(f) |
Transform each element | vec![1,2,3].iter().map(|x| x * 2).collect::<Vec<_>>() |
.filter(f) |
Keep elements matching predicate | vec![1,2,3,4].iter().filter(|&&x| x > 2).collect::<Vec<_>>() |
.filter_map(f) |
Filter + map in one step | vec!["1","hi","3"].iter().filter_map(|s| s.parse::<i32>().ok()).collect::<Vec<_>>() |
.fold(init, f) |
Accumulate into single value | vec![1,2,3].iter().fold(0, |acc, x| acc + x) // 6 |
.sum() |
Sum all elements | let total: i32 = vec![1,2,3].iter().sum(); |
.collect() |
Consume iterator into a collection | let v: Vec<i32> = (0..10).collect(); |
.enumerate() |
Pair each element with its index | for (i, val) in vec.iter().enumerate() { ... } |
.zip(other) |
Pair elements from two iterators | let pairs: Vec<_> = a.iter().zip(b.iter()).collect(); |
.chain(other) |
Concatenate two iterators | let all: Vec<_> = a.iter().chain(b.iter()).collect(); |
.take(n) |
Take first n elements | (0..).take(5).collect::<Vec<_>>() // [0,1,2,3,4] |
.skip(n) |
Skip first n elements | (0..10).skip(5).collect::<Vec<_>>() // [5,6,7,8,9] |
.flat_map(f) |
Map then flatten one level | vec![vec![1,2], vec![3]].into_iter().flat_map(|v| v).collect::<Vec<_>>() |
.any(f) / .all(f) |
Check if any/all elements match predicate | vec![1,2,3].iter().any(|&x| x > 2) // true |
.find(f) |
First element matching predicate | vec![1,2,3].iter().find(|&&x| x == 2) // Some(&2) |
.position(f) |
Index of first match | vec![1,2,3].iter().position(|&x| x == 2) // Some(1) |
.min() / .max() |
Minimum / maximum element | vec![3,1,2].iter().max() // Some(&3) |
Pattern Matching
| Pattern | Description | Example |
|---|---|---|
| Literal | Match exact values | match x { 1 => "one", 2 => "two", _ => "other" } |
| Variable binding | Bind matched value to a name | match x { n => println!("got {n}") } |
| Multiple patterns | OR with | |
match x { 1 | 2 | 3 => "small", _ => "big" } |
| Range | Match a range of values | match x { 0..=9 => "digit", _ => "other" } |
| Destructure struct | Extract struct fields | match point { Point { x, y: 0 } => println!("on x-axis at {x}"), _ => {} } |
| Destructure enum | Extract enum variant data | match msg { Message::Quit => quit(), Message::Move { x, y } => move_to(x, y) } |
| Tuple destructuring | Match tuple elements | match (x, y) { (0, 0) => "origin", (x, 0) => format!("x={x}"), _ => "other".into() } |
| Guard clause | Extra condition with if |
match x { n if n < 0 => "negative", n if n > 0 => "positive", _ => "zero" } |
@ binding |
Bind a name while matching pattern | match x { n @ 1..=5 => println!("got {n}"), _ => {} } |
| Nested patterns | Match within Option/Result | match opt { Some(0) => "zero", Some(n) => format!("{n}"), None => "none".into() } |
Wildcard _ |
Ignore a value | let (_, y, _) = (1, 2, 3); |
if let |
Match a single pattern | if let Some(val) = opt { println!("{val}"); } |
while let |
Loop while pattern matches | while let Some(top) = stack.pop() { println!("{top}"); } |
let else |
Destructure or diverge (Rust 1.65+) | let Some(val) = opt else { return; }; |
Modules & Crates
| Keyword / Pattern | Description | Example |
|---|---|---|
mod |
Declare a module | mod utils { pub fn helper() {} } |
mod (file) |
Module from separate file | mod utils; // loads utils.rs or utils/mod.rs |
pub |
Make item public | pub fn public_fn() {} |
pub(crate) |
Public within the crate only | pub(crate) fn internal_fn() {} |
pub(super) |
Public to parent module only | pub(super) fn parent_visible() {} |
use |
Bring item into scope | use std::collections::HashMap; |
use ... as |
Alias an import | use std::collections::HashMap as Map; |
use ... {} |
Multiple imports from same path | use std::io::{self, Read, Write}; |
use ... * |
Glob import (use sparingly) | use std::collections::*; |
crate:: |
Absolute path from crate root | use crate::utils::helper; |
super:: |
Path relative to parent module | use super::config::Settings; |
| External crate | Add in Cargo.toml, then use |
// Cargo.toml: serde = "1.0" |
Common Traits
| Trait | Description | Example |
|---|---|---|
Debug |
Format with {:?} for debugging |
#[derive(Debug)] struct P { x: i32 } |
Display |
Format with {} for user-facing output |
impl fmt::Display for P { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "({}, {})", self.x, self.y) } } |
Clone |
Explicit deep copy via .clone() |
#[derive(Clone)] struct P { x: i32 } |
Copy |
Implicit bitwise copy (requires Clone) | #[derive(Copy, Clone)] struct P { x: i32, y: i32 } |
PartialEq / Eq |
Equality comparison (== and !=) |
#[derive(PartialEq, Eq)] struct P { x: i32 } |
PartialOrd / Ord |
Ordering comparison (<, >, etc.) |
#[derive(PartialOrd, Ord, PartialEq, Eq)] struct P { x: i32 } |
Hash |
Produce a hash (needed for HashMap keys) | #[derive(Hash, PartialEq, Eq)] struct Id(u64); |
Default |
Default value via Default::default() |
#[derive(Default)] struct Config { verbose: bool, retries: u32 } |
From / Into |
Type conversion (implement From, get Into free) | impl From<&str> for Name { fn from(s: &str) -> Self { Name(s.to_string()) } } |
TryFrom / TryInto |
Fallible type conversion | impl TryFrom<i32> for Positive { type Error = String; fn try_from(n: i32) -> Result<Self, Self::Error> { ... } } |
Iterator |
Define custom iteration | impl Iterator for Counter { type Item = u32; fn next(&mut self) -> Option<u32> { ... } } |
Drop |
Custom cleanup when value goes out of scope | impl Drop for Resource { fn drop(&mut self) { println!("freed"); } } |
Deref / DerefMut |
Custom dereference behavior (smart pointers) | impl Deref for MyBox<T> { type Target = T; fn deref(&self) -> &T { &self.0 } } |
Macros
| Macro | Description | Example |
|---|---|---|
println!() |
Print to stdout with newline | println!("x = {x}, y = {}", y); |
eprintln!() |
Print to stderr with newline | eprintln!("Error: {err}"); |
format!() |
Format into a String (no I/O) | let s = format!("{name} is {age}"); |
dbg!() |
Debug print expression and value to stderr | dbg!(&my_vec); // prints [src/main.rs:5] &my_vec = [...] |
vec![] |
Create a Vec with initial values | let v = vec![1, 2, 3]; |
assert!() |
Assert condition is true | assert!(x > 0); |
assert_eq!() / assert_ne!() |
Assert two values are equal / not equal | assert_eq!(add(2, 3), 5); |
todo!() |
Placeholder for unfinished code (panics) | fn later() { todo!("implement this") } |
unimplemented!() |
Mark intentionally unimplemented code | fn optional_feature() { unimplemented!() } |
cfg!() |
Compile-time configuration check | if cfg!(target_os = "linux") { ... } |
#[cfg()] |
Conditional compilation attribute | #[cfg(test)] mod tests { ... } |
| Format specifiers | Control formatting output | println!("{:?}", val); // Debug |
Concurrency
| Concept | Description | Example |
|---|---|---|
thread::spawn |
Spawn a new OS thread | use std::thread; |
move closure |
Transfer ownership into thread | let data = vec![1,2,3]; |
mpsc::channel |
Multi-producer, single-consumer channel | use std::sync::mpsc; |
Mutex<T> |
Mutual exclusion lock | use std::sync::Mutex; |
Arc<T> |
Atomic reference counting for shared ownership | use std::sync::Arc; |
Arc<Mutex<T>> |
Shared mutable state across threads | let counter = Arc::new(Mutex::new(0)); |
RwLock<T> |
Multiple readers OR one writer | use std::sync::RwLock; |
Send trait |
Type can be transferred between threads | // Most types are Send. Rc<T> is NOT Send. |
Sync trait |
Type can be shared between threads via reference | // T is Sync if &T is Send. Mutex<T> is Sync. |
| Async/Await | Asynchronous programming (requires runtime) | async fn fetch() -> Result<String, Error> { ... } |
Cargo Commands
| Command | Description | Example |
|---|---|---|
cargo new |
Create a new project | cargo new my_project |
cargo build |
Compile the project | cargo build |
cargo run |
Build and run the project | cargo run |
cargo test |
Run tests | cargo test |
cargo check |
Type-check without producing binary (fast) | cargo check |
cargo add |
Add a dependency to Cargo.toml | cargo add serde --features derive |
cargo update |
Update dependencies to latest compatible versions | cargo update |
cargo doc |
Generate documentation | cargo doc --open |
cargo fmt |
Format code with rustfmt | cargo fmt |
cargo clippy |
Run the Rust linter | cargo clippy |
cargo bench |
Run benchmarks | cargo bench |
cargo publish |
Publish crate to crates.io | cargo publish |
cargo install |
Install a binary crate | cargo install ripgrep |
cargo tree |
Display dependency tree | cargo tree |
Smart Pointers
| Type | Description | Example |
|---|---|---|
Box<T> |
Heap-allocated value (single owner) | let b = Box::new(5); |
Rc<T> |
Reference counted (single-threaded shared ownership) | use std::rc::Rc; |
Arc<T> |
Atomic Rc (thread-safe shared ownership) | use std::sync::Arc; |
RefCell<T> |
Interior mutability (runtime borrow checking) | use std::cell::RefCell; |
Cell<T> |
Interior mutability for Copy types | use std::cell::Cell; |
Cow<'a, T> |
Clone-on-write (borrow or own) | use std::borrow::Cow; |
Pin<P> |
Pin a value in memory (used with async/futures) | use std::pin::Pin; |
Testing
| Pattern | Description | Example |
|---|---|---|
| Unit test | Test function with #[test] attribute |
#[test] |
| Test module | Convention: tests module with cfg(test) | #[cfg(test)] |
#[should_panic] |
Test expects a panic | #[test] |
| Result-based test | Test returns Result (use ? in tests) |
#[test] |
#[ignore] |
Skip test unless explicitly requested | #[test] |
| Integration tests | Tests in tests/ directory |
// tests/integration_test.rs |
| Doc tests | Testable examples in documentation | /// Adds two numbers. |