Cheatsheet - Rust

Tooling & CLI Commands

# Cargo project management
cargo init                      # Initialize current directory
cargo new my_project --bin      # Create new binary application
cargo new my_lib --lib          # Create new library crate

# Build & Run
cargo check                     # Fast syntax & type check without codegen
cargo build                     # Debug build with debug symbols
cargo build --release           # Fully optimized release build (LTO, inlining)
cargo run                       # Build and run target binary
cargo run --release             # Run release build

# Quality & Diagnostics
cargo test                      # Run unit and integration tests
cargo test -- --nocapture       # Run tests showing stdout
cargo clippy -- -D warnings     # Run linter catching idiomatic issues
cargo fmt --check               # Verify formatting against rustfmt
cargo tree                      # Display visual crate dependency tree

# Toolchain management (rustup)
rustup update                   # Update rustc and cargo
rustup target add aarch64-unknown-linux-musl
cargo build --target aarch64-unknown-linux-musl

Primitive Types & Variables

// Mutability & Type Inference
let x: i32 = 42;                // Immutable by default
let mut y = 100;                // Mutable variable
y += 1;

// Constants (compile-time, inlined)
const MAX_POINTS: u32 = 100_000;
static GLOBAL_NAME: &str = "APP";

// Scalar primitives
// Integers: i8, i16, i32, i64, i128, isize
// Unsigned: u8, u16, u32, u64, u128, usize
// Floats:   f32, f64
// Booleans: bool (true, false)
// Chars:    char (4-byte Unicode scalar)

// Tuples & Arrays
let tuple: (i32, f64, &str) = (500, 6.4, "rust");
let (a, b, c) = tuple;          // Destructuring pattern
let array: [i32; 4] = [1, 2, 3, 4]; // Fixed size on stack
let zeros = [0; 64];            // 64 elements of 0

Strings: &str vs String

// &str: String slice (borrowed view into memory, UTF-8 validated)
let s1: &str = "hello world";   // &'static str stored in binary .rodata

// String: Growable, heap-allocated buffer (ptr, len, cap on stack)
let mut s2 = String::from("hello");
s2.push_str(" world");

// Conversions
let s3 = s1.to_string();        // &str to owned String
let s4 = &s2[0..5];             // Substring slice (bytes 0..5)
let formatted = format!("User {}: {}", 10, "online");

Vectors & Collections

// Vec<T>: Dynamic heap-allocated array
let mut v: Vec<i32> = vec![1, 2, 3];
v.push(4);
v.pop();                        // Returns Option<i32>

let first = v[0];               // Direct index (panics if out-of-bounds)
let safe_first = v.get(0);      // Returns Option<&i32> (checked)

// HashMap
use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert("Blue", 10);
scores.entry("Yellow").or_insert(50); // Insert if absent
let score = scores.get("Blue"); // Option<&i32>

Structs & Enums

// Struct definition
struct User {
    username: String,
    active: bool,
    sign_in_count: u64,
}

// Methods and Associated Functions
impl User {
    // Associated function (constructor)
    fn new(username: &str) -> Self {
        Self {
            username: username.to_string(),
            active: true,
            sign_in_count: 0,
        }
    }

    // Method taking immutable reference
    fn is_active(&self) -> bool {
        self.active
    }

    // Method taking mutable reference
    fn record_login(&mut self) {
        self.sign_in_count += 1;
    }
}

// Enums with algebraic data types
enum WebEvent {
    PageLoad,
    KeyPress(char),
    Paste(String),
    Click { x: i64, y: i64 },
}

Pattern Matching & Control Flow

// Exhaustive match
match event {
    WebEvent::PageLoad => println!("Loaded"),
    WebEvent::KeyPress(c) => println!("Key: {}", c),
    WebEvent::Click { x, y } => println!("Clicked at ({}, {})", x, y),
    _ => (),                    // Catch-all wildcard
}

// if let and let-else
let config_val: Option<i32> = Some(10);

if let Some(val) = config_val {
    println!("Value: {}", val);
}

// Guard early return with let-else
let Some(num) = config_val else {
    return;
};

Error Handling: Option & Result

// Option<T>: Some(T) or None
let item: Option<&str> = Some("data");
let val = item.unwrap_or("default");

// Result<T, E>: Ok(T) or Err(E)
fn divide(a: f64, b: f64) -> Result<f64, String> {
    if b == 0.0 {
        Err("Division by zero".to_string())
    } else {
        Ok(a / b)
    }
}

// The ? operator for error propagation
fn run() -> Result<(), Box<dyn std::error::Error>> {
    let res = divide(10.0, 2.0)?;
    println!("Res: {}", res);
    Ok(())
}

Iterators & Functional Pipelines

let nums = vec![1, 2, 3, 4, 5, 6];

// Lazily evaluated transformation pipeline
let doubled_evens: Vec<i32> = nums
    .iter()
    .filter(|&&x| x % 2 == 0)
    .map(|&x| x * 2)
    .collect();

// Useful iterator methods
let sum: i32 = nums.iter().sum();
let found = nums.iter().find(|&&x| x > 3); // Option<&i32>
let any_odd = nums.iter().any(|&x| x % 2 != 0);

Concurrency Primitives

use std::sync::{Arc, Mutex};
use std::thread;

// Shared mutable state across threads
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];

for _ in 0..5 {
    let counter_clone = Arc::clone(&counter);
    let handle = thread::spawn(move || {
        let mut lock = counter_clone.lock().unwrap();
        *lock += 1;
    });
    handles.push(handle);
}

for h in handles {
    h.join().unwrap();
}