Rust Cheatsheet
Data Types
Use this Rust reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
Integer Types
| Type | Size | Range |
|---|---|---|
i8 | 8-bit | −128 to 127 |
i16 | 16-bit | −32,768 to 32,767 |
i32 | 32-bit | −2.1B to 2.1B (default) |
i64 | 64-bit | ±9.2×10¹⁸ |
i128 | 128-bit | ±1.7×10³⁸ |
isize | pointer-sized | platform-dependent |
u8..u128, usize | same sizes | 0 to 2ⁿ−1 |
let a: i32 = -42; let b = 255u8; let c = 1_000_000i64; // underscores for readability let hex = 0xFF; // 255 let octal = 0o17; // 15 let binary = 0b1111_0000; // 240 let byte = b'A'; // u8 value 65 // Checked arithmetic (no panic on overflow in release) let checked = 200i32.checked_add(100); // Some(300) let overflow = 127i8.checked_add(1); // None // Wrapping / saturating / overflowing let w = 127i8.wrapping_add(1); // -128 let s = 200u8.saturating_add(100); // 255 let (o, overflowed) = 200u8.overflowing_add(100); // (44, true)
Floating-Point Types
let x: f64 = 3.14; // default float type let y: f32 = 2.718; // Special values let inf = f64::INFINITY; let neg_inf = f64::NEG_INFINITY; let nan = f64::NAN; f64::is_nan(nan); // true f64::is_infinite(inf); // true f64::is_finite(3.14); // true // Constants f64::MAX // 1.7976931348623157e308 f64::MIN_POSITIVE // 2.2250738585072014e-308 f64::EPSILON // 2.220446049250313e-16 // Math methods let n: f64 = 2.0; n.sqrt() // 1.4142... n.cbrt() // cube root n.abs() // absolute value n.ceil() // 2.0 n.floor() // 2.0 n.round() // nearest integer n.trunc() // truncate decimal n.fract() // fractional part: 0.0 n.powi(3) // integer exponent: 8.0 n.powf(0.5) // float exponent: 1.414... n.exp() // eⁿ n.exp2() // 2ⁿ n.ln() // natural log n.log2() // log base 2 n.log10() // log base 10 n.log(3.0) // log base 3 n.sin() n.cos() n.tan() n.asin() n.acos() n.atan() n.atan2(1.0) // two-arg arctangent n.sinh() n.cosh() n.tanh() n.hypot(1.0) // √(n² + 1²) n.min(3.0) n.max(1.0) n.clamp(0.0, 1.0)
Boolean
let t: bool = true; let f: bool = false; // Boolean operations !t // false t && f // false (short-circuits) t || f // true (short-circuits) t & f // false (no short-circuit) t | f // true (no short-circuit) t ^ f // true (XOR) // Convert to int true as i32 // 1 false as i32 // 0
Characters
char is a Unicode scalar value — 4 bytes (not a byte!).
let c = 'z'; let emoji: char = '🦀'; let escaped = '\n'; // newline let unicode = '\u{1F600}'; // 😀 // Methods 'a'.is_alphabetic() // true '5'.is_numeric() // true (Unicode numeric) '5'.is_ascii_digit() // true ' '.is_whitespace() // true 'A'.is_uppercase() // true 'a'.is_lowercase() // true 'a'.to_uppercase().next() // Some('A') 'A'.to_lowercase().next() // Some('a') 'a' as u32 // 97 (Unicode code point) char::from(65u8) // 'A'
Tuples
Fixed-size, heterogeneous, ordered collection. Index with .0, .1, etc.
let tup: (i32, f64, bool) = (500, 6.4, true); // Destructure let (x, y, z) = tup; println!("{} {} {}", x, y, z); // Field access let five_hundred = tup.0; let six_point_four = tup.1; // Unit tuple (empty) let unit: () = (); // Single-element tuple (note the comma) let single = (42,);
Arrays
Fixed-size, same type, stack-allocated.
let arr: [i32; 5] = [1, 2, 3, 4, 5]; let zeros = [0; 10]; // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] // Access (panics on out-of-bounds) let first = arr[0]; let last = arr[4]; // Slice of array let slice: &[i32] = &arr[1..3]; // [2, 3] // Length arr.len() // 5 // Iteration for x in &arr { println!("{}", x); } for (i, x) in arr.iter().enumerate() { println!("{}: {}", i, x); }
Strings: str vs String
| Feature | &str | String |
|---|---|---|
| Allocation | Stack / static | Heap |
| Mutability | Immutable | Mutable |
| Ownership | Borrowed | Owned |
| Common use | String literals, function params | Owned, growable strings |
// &str — string slice let s: &str = "hello"; let owned = s.to_owned(); // &str → String let owned2 = String::from("hi"); // &str → String let borrowed: &str = &owned; // String → &str (deref coercion) // String creation let mut s = String::new(); let s = "initial".to_string(); let s = format!("{} {}", "hello", "world"); // Appending let mut s = String::from("hello"); s.push(' '); // push char s.push_str("world"); // push &str s += " again"; // moves s, appends (uses Add trait) let s3 = s1 + &s2; // s1 moved; s2 borrowed // String methods s.len() // byte length s.is_empty() s.contains("world") s.starts_with("hel") s.ends_with("ld") s.find("wor") // Option<usize> byte index s.rfind("l") // last occurrence s.replace("l", "r") // new String s.replacen("l", "r", 1) // replace first n s.to_uppercase() s.to_lowercase() s.trim() // strip leading+trailing whitespace s.trim_start() s.trim_end() s.trim_matches('x') // trim specific char/pattern s.split(' ') // iterator of &str s.split_whitespace() s.splitn(2, ':') // split into at most n parts s.lines() // iterate lines s.chars() // iterate Unicode chars s.bytes() // iterate bytes (u8) s.char_indices() // (byte_index, char) iterator s.parse::<i32>() // parse to type: Result<i32, _> s.repeat(3) // "abcabcabc" // Slicing (byte indices, must be char boundaries!) let hello = &s[0..5]; // Check and get chars safely s.chars().nth(0) // Option<char> s.chars().count() // number of Unicode chars // String capacity let mut s = String::with_capacity(50); s.capacity() s.reserve(10)
Vectors (Vec<T>)
Growable, heap-allocated array.
// Creation let v: Vec<i32> = Vec::new(); let v = vec![1, 2, 3]; let v = Vec::with_capacity(10); // Mutation let mut v = Vec::new(); v.push(1); v.push(2); v.pop(); // Option<T> v.insert(0, 99); // insert at index v.remove(0); // remove at index, returns element v.clear(); v.extend([4, 5, 6]); // append from iter v.append(&mut other_vec); // drains other_vec // Access v[0] // panics if out of bounds v.get(0) // Option<&T>, safe v.first() // Option<&T> v.last() // Option<&T> // Info v.len() v.is_empty() v.capacity() // Sorting v.sort(); v.sort_by(|a, b| a.cmp(b)); v.sort_by_key(|x| x.abs()); v.sort_unstable(); // faster, not stable // Search v.contains(&3) v.binary_search(&3) // Result<usize, usize> (must be sorted) v.iter().position(|&x| x == 3) // Option<usize> v.iter().find(|&&x| x > 2) // Option<&T> // Slice ops v.reverse() v.dedup() // remove consecutive duplicates v.retain(|&x| x > 0) // keep only matching v.truncate(3) // shorten to length 3 v.drain(1..3) // remove range, returns iterator v.split_at(2) // (&[T], &[T]) v.windows(3) // overlapping windows v.chunks(2) // non-overlapping chunks
HashMap
use std::collections::HashMap; let mut scores: HashMap<String, i32> = HashMap::new(); // Insert scores.insert(String::from("Alice"), 100); scores.insert(String::from("Bob"), 85); // Entry API (insert-or-update) scores.entry(String::from("Alice")).or_insert(0); // don't overwrite scores.entry(String::from("Carol")).or_insert(50); // inserts 50 *scores.entry("Bob".to_string()).or_insert(0) += 10; // update // Access scores.get("Alice") // Option<&i32> scores["Alice"] // panics if missing scores.contains_key("Alice") // bool scores.len() scores.is_empty() // Remove scores.remove("Bob"); // Option<i32> // Iteration for (key, value) in &scores { println!("{}: {}", key, value); } scores.keys() scores.values() scores.values_mut() scores.iter() scores.iter_mut() // Build from iterator let map: HashMap<&str, i32> = [("a", 1), ("b", 2)].into_iter().collect();
HashSet
use std::collections::HashSet; let mut set: HashSet<i32> = HashSet::new(); set.insert(1); set.insert(2); set.insert(1); // duplicate ignored set.contains(&1) // true set.remove(&1) set.len() // Set operations let a: HashSet<i32> = [1, 2, 3].into_iter().collect(); let b: HashSet<i32> = [2, 3, 4].into_iter().collect(); a.union(&b).collect::<HashSet<_>>() // {1,2,3,4} a.intersection(&b).collect::<HashSet<_>>() // {2,3} a.difference(&b).collect::<HashSet<_>>() // {1} a.symmetric_difference(&b) // {1,4} a.is_subset(&b) a.is_superset(&b) a.is_disjoint(&b)
Range Types
let r = 1..5; // Range<i32>: 1, 2, 3, 4 (exclusive end) let r = 1..=5; // RangeInclusive<i32>: 1, 2, 3, 4, 5 let r = 1..; // RangeFrom: 1, 2, 3, ... let r = ..5; // RangeTo: ..5 (in slices only) let r = ..=5; // RangeToInclusive let r = ..; // RangeFull: full range (in slices) for i in 0..10 { /* 0 to 9 */ } (0..5).contains(&3) // true (0..5).rev() // 4, 3, 2, 1, 0 (0..10).step_by(2) // 0, 2, 4, 6, 8
Type Aliases
type Meters = f64; type Thunk = Box<dyn Fn() -> ()>; type Result<T> = std::result::Result<T, std::io::Error>; let distance: Meters = 5.0;
The Option<T> Type
let some: Option<i32> = Some(42); let none: Option<i32> = None; // Unwrapping some.unwrap() // panics if None some.unwrap_or(0) // default if None some.unwrap_or_else(|| 0) // lazy default some.unwrap_or_default() // T::default() if None some.expect("msg") // panics with message if None // Checking some.is_some() some.is_none() // Transform some.map(|x| x * 2) // Option<i32> some.map_or(0, |x| x * 2) // i32 some.and_then(|x| Some(x + 1)) // flatMap some.or(Some(99)) // self or other if None some.or_else(|| Some(99)) some.filter(|&x| x > 0) // None if predicate false some.flatten() // Option<Option<T>> → Option<T> // Convert some.ok_or("error") // Option → Result some.as_ref() // Option<&T> some.as_mut() // Option<&mut T> some.take() // takes value, leaves None some.replace(99) // replaces value, returns old // Pattern match if let Some(x) = some { println!("{}", x); } let x = some?; // return None from fn if None (? operator)