Rust Cheat Sheet
Rust reference with ownership, borrowing, iterators, traits, error handling, and lifetimes. Copy-ready code for Rust developers.
Variables
| Syntax | Description | Example |
|---|---|---|
| Immutable variable binding | let name = "Alice"; | |
| Mutable variable binding | let mut count = 0; | |
| Compile-time constant | const MAX_SIZE: usize = 100; | |
| Static variable (global lifetime) | static VERSION: &str = "1.0"; | |
| Explicit type annotation | let age: u32 = 30; | |
| Numeric types | let x: i32 = -42; let y: f64 = 3.14; | |
| Common types | let flag: bool = true; | |
| Print with formatting | println!("Hello, {}!", name); | |
| Debug print (shows expression + value) | dbg!(x * 2); // [src/main.rs:5] x * 2 = 10 | |
| Destructuring assignment | let (x, y, z) = (1.0, 2.0, 3.0); |
Ownership
| Syntax | Description | Example |
|---|---|---|
| Move (s1 is no longer valid) | let s1 = String::from("hi"); let s2 = s1; | |
| Deep copy (both remain valid) | let s2 = s1.clone(); | |
| Immutable reference (borrow) | fn len(s: &String) -> usize { s.len() } | |
| Mutable reference (one at a time) | fn push(s: &mut String) { s.push_str("!"); } | |
| Lifetime annotation | fn first<'a>(s: &'a str) -> &'a str { ... } | |
| Static lifetime (lives forever) | let s: &'static str = "hello"; |
Strings
| Syntax | Description | Example |
|---|---|---|
| Create owned String | let s = String::from("hello"); | |
| String slice (&str) | let greeting: &str = "hello"; | |
| Byte length of string | "hello".len() // 5 | |
| Character count (Unicode-safe) | "café".chars().count() // 4 | |
| Check if string contains pattern | "hello".contains("ell") // true | |
| Check string prefix/suffix | "hello".starts_with("he") // true | |
| Replace occurrences | "hello".replace("l", "r") // "herro" | |
| Split string into iterator | "a,b,c".split(',').collect::<Vec<&str>>() | |
| Remove whitespace from both ends | " hi ".trim() // "hi" | |
| Change case | "hello".to_uppercase() // "HELLO" | |
| Format string (returns String) | format!("{} is {}", name, age) | |
| Parse string to type | "42".parse::<i32>().unwrap() // 42 | |
| Append to String | s.push_str(" world"); |
Collections
| Syntax | Description | Example |
|---|---|---|
| Create a Vec (dynamic array) | let mut nums = vec![1, 2, 3]; | |
| Add to end / remove from end | nums.push(4); let last = nums.pop(); | |
| Length / check empty | if nums.is_empty() { ... } | |
| Check if vec contains value | nums.contains(&42) // true | |
| Create iterator over references | for n in nums.iter() { println!("{}", n); } | |
| Transform each element | nums.iter().map(|x| x*2).collect::<Vec<_>>() | |
| Filter elements | nums.iter().filter(|x| **x > 1).collect::<Vec<_>>() | |
| Fold/reduce to single value | nums.iter().fold(0, |acc, x| acc + x) | |
| Iterate with index | for (i, val) in arr.iter().enumerate() { ... } | |
| Fixed-size array | let arr: [i32; 3] = [1, 2, 3]; | |
| Create a hash map | let mut map = HashMap::new(); map.insert("key", 42); | |
| Create a hash set | let mut set = HashSet::new(); set.insert(42); | |
| Collect iterator into collection | let v: Vec<i32> = (0..5).collect(); |
Control Flow
| Syntax | Description | Example |
|---|---|---|
| Conditional branching | if x > 0 { ... } else if x == 0 { ... } else { ... } | |
| Pattern match on Option | if let Some(name) = user.name { ... } | |
| Pattern matching (exhaustive) | match x { 0 => "zero", 1..=9 => "digit", _ => "big" } | |
| Infinite loop (break to exit) | loop { if done { break result; } } | |
| While loop | while count < 10 { count += 1; } | |
| For loop over iterator | for i in 0..10 { println!("{}", i); } | |
| Exit loop / skip iteration | if x == 5 { break; } | |
| Labeled loops | 'outer: for i in 0..10 { break 'outer; } |
Errors
| Syntax | Description | Example |
|---|---|---|
| Success or error type | fn parse(s: &str) -> Result<i32, ParseIntError> | |
| Some value or None | fn find(id: u32) -> Option<User> | |
| Get value or panic | let val = result.unwrap(); // panics on Err | |
| Unwrap with custom panic message | let f = File::open("data").expect("file not found"); | |
| Propagate error to caller | let data = fs::read("file.txt")?; | |
| Get value or use default | let name = opt.unwrap_or("Anonymous"); | |
| Transform Ok/Some value | opt.map(|x| x * 2) | |
| Crash with message (unrecoverable) | panic!("something went terribly wrong"); |
Types
| Syntax | Description | Example |
|---|---|---|
| Define a struct | struct Point { x: f64, y: f64 } | |
| Implement methods | impl Point { fn distance(&self) -> f64 { ... } } | |
| Define an enum | enum Color { Red, Green, Blue } | |
| Enum variants with associated data | enum Shape { Circle(f64), Rect(f64, f64) } | |
| Define a trait (interface) | trait Drawable { fn draw(&self); } | |
| Implement trait for type | impl Drawable for Circle { fn draw(&self) { ... } } | |
| Generic with trait bound | fn print<T: Display>(item: T) { println!("{}", item); } | |
| Where clause for bounds | fn process<T>(x: T) where T: Clone + Debug { ... } | |
| Auto-derive trait implementations | #[derive(Debug, Clone, PartialEq)] | |
| Trait object (dynamic dispatch) | fn get_shape() -> Box<dyn Drawable> { ... } |
Frequently asked questions
What is ownership in Rust?
Every value has exactly one owner. When the owner goes out of scope, the value is dropped (freed). Assignment moves ownership (the original variable becomes invalid). This eliminates use-after-free bugs without garbage collection.
What's the difference between String and &str?
String is an owned, heap-allocated, growable string. &str is a borrowed reference to a string slice (can point to String data or string literals). Use &str for function parameters, String when you need ownership.
When should I use clone()?
Use .clone() when you need a deep copy and can't use references. It's fine for prototyping and when the data is small. Avoid it in hot loops or with large data. Often, restructuring code to use references is better.
What are lifetimes?
Lifetimes are annotations ('a) that tell the compiler how long references are valid. They prevent dangling references. Most of the time, lifetime elision rules handle them automatically. You only annotate when the compiler can't infer relationships.
How does Rust achieve memory safety without GC?
Through ownership + borrowing rules enforced at compile time: one owner per value, unlimited immutable references OR one mutable reference, references can't outlive their data. These rules are checked by the borrow checker.
What are the most essential crates to know?
serde (serialization), tokio (async runtime), reqwest (HTTP), clap (CLI args), anyhow/thiserror (errors), tracing (logging), itertools (iterator extensions). Check lib.rs for the Rust ecosystem.
Go from reference to real skills
Cheat sheets are great for quick lookups. Our in-depth courses take you from the fundamentals to professional-level mastery.
Browse all courses