Syllabus and Snippets
This chapter is a compact Rust review sheet. The first section is only the syllabus. The later sections are recall snippets meant to make the basics easy to retrieve under interview pressure.
Syllabus
- Variables, mutability, shadowing, primitive types, tuples, arrays, and slices.
- Ownership: move, copy, drop, scope, stack vs heap.
- Borrowing:
&T,&mut T, aliasing rules, and borrow conflicts. - References and strings:
String,&str, slices, conversions. - Structs, enums,
Option,Result, and pattern matching. - Functions, methods,
impl, associated functions, modules, and visibility. - Generics, traits, trait bounds,
where,impl Trait, anddyn Trait. - Lifetimes: why they exist, elision, and borrowed return values.
- Collections:
Vec,HashMap,String, iteration, and ownership during iteration. - Iterators:
iter,iter_mut,into_iter,map,filter, andcollect. - Error handling:
Result,?, custom errors, propagation, and avoiding unnecessaryunwrap. - Smart pointers and interior mutability:
Box,Rc,Arc,RefCell,Mutex. - Concurrency: threads, channels,
Arc<Mutex<T>>,Send, andSync. - Async Rust:
async/.await, futures as state machines,tokio::spawn,select!, and blocking hazards. - Unsafe Rust and FFI: raw pointers,
unsafe, invariants, andextern "C".
Core Snippets
Variables, mutability, shadowing
fn main() { let x = 5; let mut y = 10; y += x; let y = y.to_string(); println!("{x} {y}"); }
Tuples, arrays, slices
fn main() { let pair = (42, "rust"); let nums = [1, 2, 3, 4]; let part: &[i32] = &nums[1..3]; println!("{} {}", pair.0, pair.1); println!("{part:?}"); }
Ownership and move
fn takes_ownership(s: String) { println!("{s}"); } fn main() { let s = String::from("hello"); takes_ownership(s); // s is moved here }
Copy type vs moved type
fn main() { let a = 5; let b = a; let s1 = String::from("hi"); let s2 = s1; println!("{a} {b}"); // println!("{s1}"); // moved println!("{s2}"); }
Borrowing
fn len_of(s: &String) -> usize { s.len() } fn main() { let s = String::from("hello"); let n = len_of(&s); println!("{s} {n}"); }
Mutable borrowing
fn append_world(s: &mut String) { s.push_str(" world"); } fn main() { let mut s = String::from("hello"); append_world(&mut s); println!("{s}"); }
String vs &str
fn greet(name: &str) { println!("hello, {name}"); } fn main() { let owned = String::from("bobby"); let borrowed: &str = &owned; greet(&owned); greet(borrowed); greet("rust"); }
Data Modeling Snippets
Struct and impl
#![allow(unused)] fn main() { struct User { name: String, active: bool, } impl User { fn new(name: impl Into<String>) -> Self { Self { name: name.into(), active: true, } } fn deactivate(&mut self) { self.active = false; } } }
Enum and match
#![allow(unused)] fn main() { enum State { Ready, Running(u32), Failed(String), } fn describe(state: State) -> String { match state { State::Ready => "ready".to_string(), State::Running(pid) => format!("running: {pid}"), State::Failed(msg) => format!("failed: {msg}"), } } }
Option
fn first_char(s: &str) -> Option<char> { s.chars().next() } fn main() { match first_char("rust") { Some(c) => println!("{c}"), None => println!("empty"), } }
Result
#![allow(unused)] fn main() { fn parse_port(input: &str) -> Result<u16, std::num::ParseIntError> { input.parse::<u16>() } }
if let and while let
fn main() { let maybe = Some(10); if let Some(v) = maybe { println!("{v}"); } let mut stack = vec![1, 2, 3]; while let Some(v) = stack.pop() { println!("{v}"); } }
Functions, Modules, Traits, Generics
Associated function and method
#![allow(unused)] fn main() { struct Counter(u32); impl Counter { fn new() -> Self { Self(0) } fn inc(&mut self) { self.0 += 1; } } }
Module and visibility
mod math { pub fn add(a: i32, b: i32) -> i32 { a + b } } fn main() { println!("{}", math::add(2, 3)); }
Trait and impl
#![allow(unused)] fn main() { trait Describe { fn describe(&self) -> String; } struct Job { id: u64, } impl Describe for Job { fn describe(&self) -> String { format!("job: {}", self.id) } } }
Generic function with trait bound
#![allow(unused)] fn main() { fn print_twice<T: std::fmt::Display>(value: T) { println!("{value}"); println!("{value}"); } }
where clause
#![allow(unused)] fn main() { fn pair_to_string<T, U>(a: T, b: U) -> String where T: std::fmt::Display, U: std::fmt::Display, { format!("{a}:{b}") } }
impl Trait and dyn Trait
#![allow(unused)] fn main() { fn make_iter() -> impl Iterator<Item = i32> { vec![1, 2, 3].into_iter() } fn describe_dyn(x: &dyn std::fmt::Display) { println!("{x}"); } }
Lifetime Snippets
Borrowed return value
#![allow(unused)] fn main() { fn longest<'a>(a: &'a str, b: &'a str) -> &'a str { if a.len() >= b.len() { a } else { b } } }
Lifetime in struct
#![allow(unused)] fn main() { struct View<'a> { text: &'a str, } }
Collections and Iterator Snippets
Vec
fn main() { let mut nums = vec![1, 2, 3]; nums.push(4); for n in &nums { println!("{n}"); } }
HashMap
use std::collections::HashMap; fn main() { let mut counts = HashMap::new(); counts.insert("rust", 2); counts.entry("tokio").or_insert(1); }
iter, iter_mut, into_iter
fn main() { let mut nums = vec![1, 2, 3]; for n in nums.iter() { println!("{n}"); } for n in nums.iter_mut() { *n *= 2; } for n in nums.into_iter() { println!("{n}"); } }
Iterator pipeline
fn main() { let nums = vec![1, 2, 3, 4, 5, 6]; let evens: Vec<i32> = nums .into_iter() .filter(|n| n % 2 == 0) .map(|n| n * 10) .collect(); println!("{evens:?}"); }
Error Handling Snippets
? operator
#![allow(unused)] fn main() { use std::fs; use std::io; fn read_config() -> Result<String, io::Error> { let contents = fs::read_to_string("config.toml")?; Ok(contents) } }
Custom error enum
#![allow(unused)] fn main() { #[derive(Debug)] enum AppError { Io(std::io::Error), Parse(std::num::ParseIntError), } impl From<std::io::Error> for AppError { fn from(err: std::io::Error) -> Self { AppError::Io(err) } } impl From<std::num::ParseIntError> for AppError { fn from(err: std::num::ParseIntError) -> Self { AppError::Parse(err) } } }
Smart Pointer and Concurrency Snippets
Box
#![allow(unused)] fn main() { enum List { Cons(i32, Box<List>), Nil, } }
Rc
use std::rc::Rc; fn main() { let a = Rc::new(String::from("shared")); let b = Rc::clone(&a); println!("{a} {b}"); }
Arc<Mutex<T>>
use std::sync::{Arc, Mutex}; use std::thread; fn main() { let count = Arc::new(Mutex::new(0)); let mut handles = Vec::new(); for _ in 0..4 { let count = Arc::clone(&count); handles.push(thread::spawn(move || { let mut guard = count.lock().unwrap(); *guard += 1; })); } for handle in handles { handle.join().unwrap(); } println!("{}", *count.lock().unwrap()); }
Channel
use std::sync::mpsc; use std::thread; fn main() { let (tx, rx) = mpsc::channel(); thread::spawn(move || { tx.send(String::from("hello")).unwrap(); }); println!("{}", rx.recv().unwrap()); }
Send and Sync mental model
#![allow(unused)] fn main() { // Send: value can move to another thread. // Sync: shared reference can be used from another thread. }
Recall Checklist
- Can I explain move vs borrow vs mutable borrow without hesitation?
- Can I explain
Stringvs&str? - Can I model absence with
Optionand failure withResult? - Can I write a
struct,enum,impl, andmatchfrom memory? - Can I explain trait bounds and when to use
dyn Trait? - Can I explain what lifetimes are protecting?
- Can I use
Vec,HashMap, and iterators comfortably? - Can I explain
Arc<Mutex<T>>,Send, andSync? - Can I explain the basics well enough before moving on to async and unsafe?