Rust Cheat Sheet
A minimal, senior-style reference for when I eventually get serious with Rust.
Strictly typed, memory-safe, and zero-cost abstractions — even when I don’t fully get it yet.
Project Structure
cargo new my_project # creates src/main.rs
cargo build # compile
cargo run # build & run
cargo check # type check only
cargo test # run tests
File layout:
src/
main.rs // binary entry point
lib.rs // optional library module
Cargo.toml // dependency & metadata
Variables & Types
let x = 42; // immutable by default
let mut y = 5; // mutable
const PI: f64 = 3.14; // compile-time const
let s: &str = "hello"; // string slice
let name: String = String::from("hi"); // owned heap-allocated string
let t: (i32, bool) = (42, true);
let [a, b, c]: [i32; 3] = [1, 2, 3];
Functions
fn square(x: i32) -> i32 {
x * x
}
fn unit_function() {
println!("no return");
}
Closures:
let add = |a, b| a + b;
let captured = |x: i32| x + y;
Control Flow
if n > 0 {
println!("positive");
} else if n == 0 {
println!("zero");
} else {
println!("negative");
}
let result = if cond { 1 } else { 0 };
match x {
1 => println!("one"),
2 | 3 => println!("two or three"),
_ => println!("something else"),
}
while i < 10 { ... }
for i in 0..5 { ... }
loop { break; }
Ownership, Borrowing & Lifetimes
T
– owned&T
– shared reference (borrow)&mut T
– mutable reference (borrow)- Lifetimes: explicit when needed (
<'a>
), but inferred when possible
fn borrow(x: &i32) {
println!("{}", x);
}
fn borrow_mut(x: &mut i32) {
*x += 1;
}
Can only have:
- one mutable reference OR
- multiple immutable references
at the same time.
Structs & Enums
struct Point {
x: f64,
y: f64,
}
enum Result<T, E> {
Ok(T),
Err(E),
}
Associated functions:
impl Point {
fn new(x: f64, y: f64) -> Self {
Self { x, y }
}
}
Pattern Matching & Destructuring
let (a, b) = (1, 2);
match maybe_value {
Some(x) => println!("{}", x),
None => println!("Nothing"),
}
if let Some(x) = opt {
println!("Found: {}", x);
}
Traits & Generics
trait Speak {
fn speak(&self);
}
impl Speak for Dog {
fn speak(&self) {
println!("Woof");
}
}
fn print_all<T: Display>(items: &[T]) {
for i in items {
println!("{}", i);
}
}
Trait bounds via where
:
fn log<T>(item: T)
where
T: Debug + Clone,
{
println!("{:?}", item);
}
Modules & Visibility
mod mymod {
pub fn hello() { ... }
}
use crate::mymod::hello;
Public API must be explicitly exposed with pub
.
Error Handling
fn might_fail() -> Result<i32, String> {
if success {
Ok(42)
} else {
Err("something broke".into())
}
}
let result = might_fail()?;
Result<T, E>
is the standard way to model recoverable errors.- Use
?
to propagate.
Smart Pointers
Box<T>
: heap allocationRc<T>
: shared ownershipRefCell<T>
: interior mutabilityArc<T>
: atomic Rc for threads
Macros
println!("Hello, {}", name);
dbg!(x);
vec![1, 2, 3];
Custom macros use macro_rules!
.
Concurrency
use std::thread;
let handle = thread::spawn(|| {
// do work
});
handle.join().unwrap();
- Use
Mutex<T>
,Arc<T>
for shared state. - Prefer message-passing via
channel()
when possible.
Crates & Cargo
In Cargo.toml
:
[dependencies]
regex = "1.9"
serde = { version = "1.0", features = ["derive"] }
Then:
use regex::Regex;
Best Practices
- Use
Option<T>
andResult<T, E>
instead ofnull
- Avoid cloning unless necessary — understand ownership
unwrap()
only in examples or panic-safe places- Use
cargo fmt
andclippy
for linting - Avoid premature lifetimes unless compiler demands them
- Use
?
andmatch
for clean error flow