contentintech
Learn/languages/Rust/Cheatsheet
Advanced

Rust Cheatsheet

A quick-reference cheatsheet for Rust syntax, ownership and borrowing rules, traits, generics, collections, iterators, smart pointers, concurrency, and cargo commands.

OwnershipBorrowingTraitsPattern Matching
NotesCheatsheet

Variables & Types

Bindings

let x = 5;              // immutable
let mut y = 10;         // mutable
let x = x + 1;          // shadowing (new binding)
const MAX: u32 = 100;   // compile-time constant, typed

Types

i8 i16 i32 i64 i128 isize    // signed integers
u8 u16 u32 u64 u128 usize    // unsigned
f32 f64  bool  char          // scalars
let tup: (i32, char) = (1, 'a');   let a = tup.0;
let arr: [i32; 3] = [1, 2, 3];     let s = &arr[0..2]; // slice

Ownership & Borrowing

Move / Copy / Clone

let s2 = s1;          // MOVE: s1 invalid (heap types)
let s3 = s2.clone();  // deep copy
let n2 = n1;          // COPY: primitives implement Copy

Reference Rules

Reference Rule
&TMany shared (read-only) refs allowed.
&mut TExactly one, and no shared refs at same time.
LifetimeA ref may not outlive its referent.
fn len(s: &String) -> usize { s.len() }  // borrow
fn push(v: &mut Vec<i32>) { v.push(1); } // mutable borrow
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { x } // lifetime

Functions & Control Flow

fn add(a: i32, b: i32) -> i32 { a + b } // last expr returned

let n = if a > b { a } else { b };      // if is an expression
for i in 0..5 { }                        // range
while cond { }
let x = loop { break 42; };              // loop returns a value

Structs & Enums

struct Point { x: f64, y: f64 }

impl Point {
    fn new(x: f64, y: f64) -> Self { Point { x, y } }
    fn dist(&self) -> f64 { (self.x.powi(2) + self.y.powi(2)).sqrt() }
}

enum Shape {
    Circle(f64),              // tuple variant
    Rect { w: f64, h: f64 },  // struct variant
    Unit,
}

Pattern Matching

match shape {
    Shape::Circle(r) => 3.14 * r * r,
    Shape::Rect { w, h } => w * h,
    Shape::Unit => 0.0,
}

if let Some(x) = opt { }         // single-pattern
while let Some(t) = stack.pop() { }
match n { 1 | 2 => "low", 3..=9 => "mid", _ => "high" };
let (a, .., z) = (1, 2, 3, 4);   // destructure with rest

Option, Result & ?

enum Option<T> { Some(T), None }
enum Result<T, E> { Ok(T), Err(E) }

fn parse(s: &str) -> Result<i32, std::num::ParseIntError> {
    let n: i32 = s.parse()?;  // ? returns Err early
    Ok(n * 2)
}

let v = opt.map(|n| n * 2).unwrap_or(0);
let x = res.expect("must succeed"); // panics on Err

Traits & Generics

trait Speak {
    fn name(&self) -> String;
    fn greet(&self) -> String { format!("Hi {}", self.name()) } // default
}

impl Speak for Dog { fn name(&self) -> String { "Rex".into() } }

#[derive(Debug, Clone, PartialEq)] struct P { x: i32 } // derive

fn largest<T: PartialOrd + Copy>(list: &[T]) -> T { list[0] }
fn show<T>(x: T) where T: std::fmt::Display { println!("{x}"); }

let objs: Vec<Box<dyn Speak>> = vec![Box::new(Dog {})]; // trait object

Collections

let mut v: Vec<i32> = vec![1, 2, 3];
v.push(4);   let slice: &[i32] = &v[1..];

let mut s = String::from("Hi");   s.push_str(", there");

use std::collections::HashMap;
let mut m: HashMap<String, i32> = HashMap::new();
m.insert("a".into(), 1);
*m.entry("a".into()).or_insert(0) += 5; // upsert

Iterators & Closures

let out: Vec<i32> = nums.iter()
    .filter(|&&n| n % 2 == 0) // lazy
    .map(|&n| n * n)         // lazy
    .collect();               // consumer runs the chain

let total: i32 = nums.iter().sum();
let factor = 10;
let scale = |x: i32| x * factor;  // closure captures env
nums.iter().for_each(|n| println!("{n}"));

Smart Pointers

Type Use
Box<T>Single-owner heap allocation.
Rc<T>Shared ownership, single thread.
Arc<T>Shared ownership across threads.
RefCell<T>Interior mutability, runtime-checked.
use std::rc::Rc; use std::cell::RefCell;
let shared = Rc::new(RefCell::new(vec![1]));
let clone = Rc::clone(&shared);
clone.borrow_mut().push(2);

Concurrency

use std::sync::{Arc, Mutex}; use std::thread;
let c = Arc::new(Mutex::new(0));
let h = { let c = Arc::clone(&c);
    thread::spawn(move || { *c.lock().unwrap() += 1; }) };
h.join().unwrap();

use std::sync::mpsc;               // channels
let (tx, rx) = mpsc::channel();
thread::spawn(move || tx.send(1).unwrap());
let got = rx.recv().unwrap();

#[tokio::main] async fn main() { let x = fetch().await; } // async

Cargo Commands

cargo new my_proj        # create a new project
cargo build              # compile (add --release to optimize)
cargo run                # build and run
cargo test               # run tests
cargo clippy             # lint for idioms and mistakes
cargo fmt                # format with rustfmt
cargo add serde          # add a dependency

Section navigation