Rust Cheatsheet
Control Flow
Use this Rust reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
if / else if / else
if is an expression — it returns a value.
let number = 7; if number < 5 { println!("less than 5"); } else if number == 5 { println!("equal to 5"); } else { println!("greater than 5"); } // As expression (arms must return same type) let msg = if number % 2 == 0 { "even" } else { "odd" }; // In let binding let abs = if number >= 0 { number } else { -number };
loop
Infinite loop; use break to exit, continue to skip.
loop { println!("again!"); break; // exit } // Return a value from loop let mut counter = 0; let result = loop { counter += 1; if counter == 10 { break counter * 2; // break with value } }; // result == 20
while
let mut n = 0; while n < 5 { println!("{}", n); n += 1; } // while let: loop while pattern matches let mut stack = vec![1, 2, 3]; while let Some(top) = stack.pop() { println!("{}", top); }
for Loops
// Range for i in 0..5 { print!("{} ", i); } // 0 1 2 3 4 for i in 0..=5 { print!("{} ", i); } // 0 1 2 3 4 5 for i in (0..5).rev() { print!("{} ", i); } // 4 3 2 1 0 // Iterator over collection (borrows) let v = vec![10, 20, 30]; for x in &v { println!("{}", x); } // &i32 for x in &mut v { *x += 1; } // &mut i32 for x in v { println!("{}", x); } // i32, v consumed // Enumerate for (i, x) in v.iter().enumerate() { println!("[{}] = {}", i, x); } // Zip let keys = ["a", "b", "c"]; let vals = [1, 2, 3]; for (k, v) in keys.iter().zip(vals.iter()) { println!("{}: {}", k, v); } // Step for i in (0..20).step_by(5) { print!("{} ", i); } // 0 5 10 15
Loop Labels
Labels allow breaking/continuing an outer loop from an inner one.
'outer: for i in 0..5 { 'inner: for j in 0..5 { if i == 2 && j == 2 { break 'outer; // break the outer loop } if j == 3 { continue 'outer; // continue the outer loop } println!("({}, {})", i, j); } }
match
Exhaustive pattern matching — must cover all cases. Each arm is pattern => expression.
let x = 5; match x { 1 => println!("one"), 2 | 3 => println!("two or three"), // OR pattern 4..=6 => println!("four to six"), // range pattern n @ 7..=9 => println!("binding: {}", n), // bind to variable _ => println!("something else"), // wildcard/catch-all } // Return a value from match let description = match x { 1 => "one", 2..=9 => "single digit", _ => "large", }; // Match on multiple values (tuple) let pair = (true, 42); match pair { (true, y) if y > 0 => println!("true and positive: {}", y), (true, _) => println!("true but not positive"), (false, 0) => println!("false and zero"), _ => println!("other"), }
Match Guards
Extra condition after the pattern, using if:
let num = Some(4); match num { Some(x) if x < 5 => println!("less than 5: {}", x), Some(x) => println!("{}", x), None => (), }
Destructuring in Patterns
// Struct struct Point { x: i32, y: i32 } let p = Point { x: 3, y: 7 }; let Point { x, y } = p; // shorthand let Point { x: a, y: b } = p; // rename to a, b // Tuple struct struct Color(i32, i32, i32); let Color(r, g, b) = Color(255, 0, 0); // Tuple let (a, b, c) = (1, 2, 3); let (head, ..) = (1, 2, 3, 4); // ignore rest let (.., tail) = (1, 2, 3, 4); // Enum (see Enums page) // Nested let ((a, b), c) = ((1, 2), 3); // Slice let [first, second, rest @ ..] = [1, 2, 3, 4][..] else { return; };
if let
Concise match for a single pattern:
let some_value: Option<i32> = Some(7); if let Some(x) = some_value { println!("Got {}", x); } else { println!("Nothing"); } // With enums if let Ok(n) = "42".parse::<i32>() { println!("Parsed: {}", n); }
let-else
Run a block if the pattern does NOT match (block must diverge: return, break, continue, or panic!):
fn get_name(opt: Option<String>) -> String { let Some(name) = opt else { return String::from("unknown"); }; name } let Ok(n) = "42".parse::<i32>() else { panic!("failed to parse"); };
matches! Macro
let x = 5; let is_small = matches!(x, 1..=9); // true let is_one_or_two = matches!(x, 1 | 2); // false let opt = Some(42); let has_value = matches!(opt, Some(n) if n > 0); // true
Iterators and Functional Control Flow
Iterators are lazy — they do nothing until consumed.
let v = vec![1, 2, 3, 4, 5]; // Creating iterators v.iter() // yields &T v.iter_mut() // yields &mut T v.into_iter() // yields T (consumes v) // Adapters (lazy) .map(|x| x * 2) .filter(|x| x % 2 == 0) .filter_map(|x| if x > 0 { Some(x * 2) } else { None }) .flat_map(|x| vec![x, x + 1]) .flatten() .take(3) // first 3 items .take_while(|x| x < &4) .skip(2) .skip_while(|x| x < &3) .enumerate() // (index, value) .zip(other.iter()) // combine two iterators .chain(other.iter()) // concatenate iterators .peekable() // peek at next without consuming .rev() // reverse (requires ExactSizeIterator) .cloned() // &T → T for Copy/Clone types .copied() // &T → T for Copy types .inspect(|x| dbg!(x)) // side-effect for debugging .step_by(2) .cycle() // infinite repetition .distinct_by(|x| x) // (external crate) // Consumers (eager — trigger evaluation) .collect::<Vec<_>>() .collect::<HashMap<K, V>>() .collect::<String>() .sum::<i32>() .product::<i32>() .count() .min() .max() .min_by_key(|x| x.abs()) .max_by(|a, b| a.cmp(b)) .find(|&&x| x > 2) // Option<&T> .find_map(|x| if x > 2 { Some(x * 10) } else { None }) .position(|&x| x == 3) // Option<usize> .any(|&x| x > 3) // bool .all(|&x| x > 0) // bool .fold(0, |acc, x| acc + x) // reduce with accumulator .reduce(|acc, x| acc + x) // fold without initial (Option) .for_each(|x| println!("{}", x)) .last() // Option<T> .nth(2) // Option<T> .partition(|&&x| x % 2 == 0) // (Vec<T>, Vec<T>) .unzip() // (Vec<A>, Vec<B>) from Vec<(A,B)>
// Example pipeline let result: Vec<i32> = (1..=10) .filter(|x| x % 2 == 0) .map(|x| x * x) .take(3) .collect(); // [4, 16, 36]
Diverging Expressions (!)
// `!` type — never returns fn forever() -> ! { loop {} } fn error_out(msg: &str) -> ! { panic!("{}", msg); } // panic!, process::exit, loop {}, etc. all have type `!` // This lets them appear in any branch without type mismatch: let x: i32 = match some_opt { Some(n) => n, None => panic!("expected value"), // ! coerces to i32 };