Rust Cheatsheet
Quick reference for Rust basics — data structures, functions, control flow, ownership, and concurrency.
Data Structures
| Structure |
Syntax |
Notes |
| Array |
[1, 2, 3] |
Fixed size, stack-allocated |
| Vec |
vec![1, 2, 3] |
Growable, heap-allocated |
| Tuple |
("Ada", 30) |
Heterogeneous, fixed size |
| HashMap |
HashMap::new() |
Key-value, requires use |
| HashSet |
HashSet::new() |
Unique values |
| Slice |
&v[1..3] |
Borrowed view into a sequence |
Functions
// Basic function
fn greet(name: &str) -> String {
format!("Hello, {}", name)
}
// Multiple return values via tuple
fn divmod(a: i32, b: i32) -> (i32, i32) {
(a / b, a % b)
}
// Ownership transfer (move)
fn take_ownership(s: String) {
println!("{}", s);
} // s dropped here
// Borrow (reference)
fn borrow(s: &String) -> i32 {
s.len() as i32
}
// Mutable borrow
fn modify(s: &mut String) {
s.push_str("!");
}
// Generic function
fn first<T>(v: &[T]) -> Option<&T> {
v.first()
}
// Closures
let square = |x: i32| x * x;
let greet = |name: &str| format!("Hi, {}", name);
Variables & Types
// Immutable by default
let x = 42;
let mut y = 42; // mutable
y = 99;
// Type annotations
let name: &str = "Ada";
let age: u32 = 30;
let pi: f64 = 3.14159;
// Constants (must be typed, compile-time eval)
const MAX_SIZE: usize = 1024;
// Shadowing (reuse name with new type)
let x = 5;
let x = x * 2; // x is now 10, can change type
// Type aliases
type Kilometers = i32;
Strings
let s: String = String::from("hello"); // owned, heap
let slice: &str = "hello"; // borrowed, static
// Convert between them
let s2 = slice.to_string(); // &str -> String
let s3 = s.clone(); // deep copy
let view: &str = &s; // String -> &str
// String operations
let msg = format!("Hello, {}!", name);
let msg = format!("{:?}, {:#?}", data, data); // debug format
let len = msg.len();
let bytes = msg.as_bytes();
let chars: Vec<char> = msg.chars().collect();
Option & Result
// Option<T> replaces null
let some: Option<i32> = Some(42);
let none: Option<i32> = None;
// Unwrapping (panics on None)
let val = some.unwrap();
let val = some.unwrap_or(0);
let val = some.unwrap_or_default();
// Pattern matching
match some {
Some(v) => println!("{}", v),
None => println!("nothing"),
}
// if let
if let Some(v) = some {
println!("{}", v);
}
// Result<T, E> replaces exceptions
let result: Result<i32, &str> = Ok(42);
let err: Result<i32, &str> = Err("failed");
// The ? operator propagates errors
fn read_file(path: &str) -> Result<String, std::io::Error> {
let content = std::fs::read_to_string(path)?;
Ok(content)
}
Loops & Iterators
// for loop
for i in 0..5 {
println!("{}", i); // 0, 1, 2, 3, 4
}
// for over iterator
for item in vec.iter() { }
for item in vec.iter_mut() { }
for (i, item) in vec.iter().enumerate() { }
// while
let mut n = 0;
while n < 5 {
n += 1;
}
// loop (infinite, break to exit)
let mut count = 0;
loop {
count += 1;
if count >= 5 { break; }
}
// Iterator methods (like JS array methods)
let doubled: Vec<i32> = nums.iter().map(|x| x * 2).collect();
let evens: Vec<i32> = nums.iter().filter(|x| *x % 2 == 0).copied().collect();
let sum: i32 = nums.iter().sum();
let has_any = nums.iter().any(|x| *x > 5);
let found = nums.iter().find(|x| **x == 3);
let (evens, odds): (Vec<i32>, Vec<i32>) = nums.iter()
.partition(|x| *x % 2 == 0);
Pattern Matching
// Exhaustive match
enum Direction { Up, Down, Left, Right }
fn move_player(dir: Direction) {
match dir {
Direction::Up => println!("up"),
Direction::Down => println!("down"),
Direction::Left | Direction::Right => println!("horizontal"),
}
}
// Destructuring enums with data
enum Shape {
Circle { radius: f64 },
Rect { w: f64, h: f64 },
}
fn area(s: Shape) -> f64 {
match s {
Shape::Circle { radius } => std::f64::consts::PI * radius * radius,
Shape::Rect { w, h } => w * h,
}
}
// Match guards
match x {
n if n > 0 => println!("positive"),
0 => println!("zero"),
_ => println!("negative"),
}
Structs, Enums & Traits
// Struct
struct User {
name: String,
age: u32,
}
// Struct methods via impl
impl User {
fn new(name: String, age: u32) -> Self {
Self { name, age }
}
fn greet(&self) -> String {
format!("Hi, I'm {}", self.name)
}
fn have_birthday(&mut self) {
self.age += 1;
}
}
// Trait (like interface)
trait Greets {
fn greet(&self) -> String;
}
impl Greets for User {
fn greet(&self) -> String {
format!("Hi, I'm {}", self.name)
}
}
// Enum with data
enum Result<T, E> {
Ok(T),
Err(E),
}
Concurrency
use std::thread;
use std::sync::mpsc;
use std::sync::{Arc, Mutex};
// Spawning threads
let handle = thread::spawn(|| {
"hello from thread"
});
let result = handle.join().unwrap();
// Channels (message passing)
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
tx.send(42).unwrap();
});
let val = rx.recv().unwrap();
// Shared state with Mutex + Arc
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
handles.push(thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
}));
}
for h in handles { h.join().unwrap(); }
Cargo Commands
| Command |
Purpose |
cargo new myproject |
Create new project |
cargo build |
Compile (debug) |
cargo build --release |
Compile (optimized) |
cargo run |
Build and run |
cargo test |
Run tests |
cargo check |
Type-check only (fast) |
cargo fmt |
Format code |
cargo clippy |
Lint code |
cargo add <crate> |
Add dependency |
cargo doc --open |
Generate and open docs |