Advanced
A quick-reference cheatsheet for Rust syntax, ownership and borrowing rules, traits, generics, collections, iterators, smart pointers, concurrency, and cargo commands.
OwnershipBorrowingTraitsPattern Matching
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 |
&T | Many shared (read-only) refs allowed. |
&mut T | Exactly one, and no shared refs at same time. |
| Lifetime | A 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