Rust logoRust ADVANCED

Rust

Comprehensive Rust reference covering ownership, borrowing, structs, enums, traits, generics, error handling, async/await, concurrency, macros, and more.

15 min read
rustsystemsmemory-safetyconcurrencyperformance

Getting Started

Install Rust, create a project with Cargo, and run your first program.

Installation & Cargo

Install Rust with rustup and use Cargo to create and run projects.

rust
💡 Use "cargo check" instead of "cargo build" for fast type-checking during development
⚡ cargo clippy catches common mistakes and suggests idiomatic improvements
📌 println! uses {} for Display, {:?} for Debug, and {:#?} for pretty-printed Debug
🟢 Add dependencies to Cargo.toml — Cargo downloads and compiles them automatically
installcargosetup

Variables & Types

Variables, mutability, basic types, tuples, arrays, and type aliases.

Variables & Basic Types

Declare variables with let, control mutability, and use primitive types.

rust
💡 Variables are immutable by default — add mut only when you need to change the value
⚡ Shadowing lets you reuse a name with a different type — unlike mut which keeps the type
📌 Use underscores in numeric literals for readability: 100_000 instead of 100000
🟢 Tuples destructure with let (x, y) = tup; arrays access with arr[0]
variablestypesmutability

Strings

Understand &str vs String, conversions, and string operations.

&str vs String

The two string types, when to use each, and how to convert between them.

rust
💡 Use &str for function parameters — it accepts both &str and &String (via deref coercion)
⚡ format!() creates a new String — like println! but returns instead of printing
📌 .len() returns bytes, not characters — use .chars().count() for Unicode char count
🟢 Rule of thumb: accept &str, return String — gives callers maximum flexibility
stringsstrstringconversions

Control Flow

If expressions, loops, match, if let, and pattern matching.

If, Loops & Match

Conditional expressions, loops, and pattern matching.

rust
💡 if and match are expressions — they return values, so you can assign them to variables
⚡ if let is sugar for matching a single pattern — cleaner than a full match for Option/Result
📌 let-else (let Some(x) = val else { return }) is the idiomatic "unwrap or bail" pattern
🟢 Match is exhaustive — the compiler forces you to handle every possible case
ifloopsmatchpattern-matching

Functions & Closures

Define functions, closures, and understand Fn traits.

Functions & Closures

Named functions, closures, and the Fn/FnMut/FnOnce traits.

rust
💡 No semicolon on the last expression makes it the return value — this is idiomatic Rust
⚡ Closures infer types from usage — you rarely need type annotations on them
📌 Use move || to force a closure to take ownership — required for spawning threads
🟢 Fn (immutable borrow) > FnMut (mutable borrow) > FnOnce (ownership) — most closures are Fn
functionsclosuresfn-traits

Ownership & Borrowing

Rust's ownership system, borrowing rules, and Clone vs Copy.

Ownership & Borrowing

Move semantics, borrowing rules, and the Clone/Copy distinction.

rust
💡 Copy types (i32, f64, bool, char) are copied on assignment; heap types (String, Vec) are moved
⚡ The rule: either one &mut OR many & — never both at the same time
📌 When a function takes a value (not a reference), ownership is moved and the caller loses it
🟢 Use .clone() when you need two owners — but prefer borrowing when possible
ownershipborrowingreferencesmoveclone

Structs & Enums

Define custom types with structs and enums, and attach methods with impl.

Structs & Methods

Define structs and attach methods with impl blocks.

rust
💡 &self borrows, &mut self borrows mutably, self takes ownership — pick the least powerful one
⚡ Self is an alias for the struct type inside impl blocks — use it in constructors
📌 Struct update syntax (..other) moves fields from other — clone first if you still need it
🟢 Convention: use new() as the constructor name, like User::new()
structsmethodsimpl

Enums

Define enums with variants that can hold data.

rust
💡 Option<T> replaces null — Some(value) or None, compiler forces you to handle both
⚡ Use matches!(val, Pattern) for quick boolean pattern checks without a full match
📌 Each enum variant can hold different types and amounts of data — much more powerful than C enums
🟢 .unwrap() panics on None — prefer .unwrap_or(), .map(), or if let in production code
enumsoptionmatchvariants

Traits

Define shared behavior with traits, derive common traits, and use From/Into.

Defining & Implementing Traits

Create traits, implement them for types, and use trait bounds.

rust
💡 impl Trait in parameters = static dispatch (monomorphized); dyn Trait = dynamic dispatch (vtable)
⚡ Use where clauses when trait bounds get complex — much more readable than inline bounds
📌 Trait objects (Box<dyn Trait>) let you store different types in one collection
🟢 impl Trait in return position means "returns some type implementing Trait" — great for closures
traitsboundsdynimpl-trait

Common Traits & Derive

Derive traits automatically and implement From/Into for conversions.

rust
💡 Implementing From<T> gives you Into<T> for free — always implement From, not Into
⚡ #[derive(Default)] gives you Config::default() — all fields use their type's default (0, "", false)
📌 Copy can only be derived if all fields are Copy — String is not Copy, so structs with String can't be
🟢 Operator overloading uses traits from std::ops — Add for +, Sub for -, Mul for *, Index for []
derivefromintodisplayoperator-overloading

Generics & Lifetimes

Write generic code and annotate lifetimes for references.

Generics & Lifetimes

Generic functions, structs, and lifetime annotations.

rust
💡 Lifetimes don't change how long data lives — they help the compiler verify references are valid
⚡ Most lifetimes are inferred (elision rules) — you only annotate when the compiler asks
📌 'static means the reference can live for the entire program — string literals are 'static
🟢 Rule: if a function returns a reference, it must come from an input — not from local data
genericslifetimesbounds

Error Handling

Handle errors with Result, Option, the ? operator, and custom error types.

Result, Option & the ? Operator

Propagate errors idiomatically with Result<T, E> and the ? operator.

rust
💡 The ? operator replaces verbose match/unwrap patterns — it's the idiomatic way to propagate errors
⚡ Implement From<OtherError> for your error type — then ? auto-converts between error types
📌 Use Box<dyn Error> as a quick return type when you don't want a custom error enum
🟢 In production, use the anyhow crate for applications and thiserror for libraries
resultoptionerror-handlingquestion-mark

Collections & Iterators

Vec, HashMap, and iterator methods for transforming data.

Vec & HashMap

Dynamic arrays and key-value maps.

rust
💡 Use v.get(i) instead of v[i] to avoid panics — returns Option<&T>
⚡ The entry().or_insert() pattern is the idiomatic way to insert-if-absent in HashMaps
📌 .collect() can build Vec, HashMap, String, and more — the target type determines behavior
🟢 Use &v to borrow during iteration, v to consume, &mut v to mutate in place
vechashmapcollections

Iterators

Transform collections with iterator adaptors and consumers.

rust
💡 Iterators are lazy — .map() and .filter() do nothing until you .collect() or .sum()
⚡ .iter() borrows, .into_iter() consumes, .iter_mut() mutably borrows the collection
📌 Use turbofish ::<Vec<_>> with .collect() when the compiler can't infer the target type
🟢 Chain adaptors freely — Rust optimizes iterator chains to be as fast as hand-written loops
iteratorsmapfiltercollect

Smart Pointers

Box, Rc, Arc, RefCell, and Cow for advanced memory management.

Box, Rc, Arc & RefCell

Heap allocation, reference counting, and interior mutability.

rust
💡 Box is for heap allocation — use it for recursive types, large data, and dyn Trait
⚡ Rc is for multiple owners in one thread; Arc is the thread-safe version — same API
📌 RefCell moves borrow checking from compile time to runtime — panics if rules are violated
🟢 Cow<str> avoids cloning when you might or might not need to modify a string
boxrcarcrefcellcowsmart-pointers

Concurrency

Threads, channels, Arc, and Mutex for safe concurrent programming.

Threads, Channels & Mutex

Spawn threads, pass messages, and share state safely.

rust
💡 Arc<Mutex<T>> is the standard pattern for shared mutable state across threads
⚡ Channels (mpsc) are for message passing; Mutex is for shared state — pick one paradigm
📌 Mutex::lock() returns a MutexGuard — it auto-unlocks when the guard is dropped
🟢 Send + Sync traits are auto-implemented — the compiler prevents unsafe sharing at compile time
threadschannelsmutexarcconcurrency

Async Programming

Async/await with tokio for non-blocking I/O.

Async/Await & Tokio

Write async functions and use the tokio runtime.

rust
💡 async fn returns a Future — nothing happens until you .await it
⚡ tokio::join! runs futures concurrently; sequential .await runs them one after another
📌 Use tokio::sync::Mutex (not std::sync::Mutex) in async code — it doesn't block the runtime
🟢 tokio::spawn creates lightweight tasks — much cheaper than OS threads
asyncawaittokiofutures

Macros & File I/O

Define macros with macro_rules! and read/write files with std::fs.

Macros

Write declarative macros with macro_rules! for code generation.

rust
💡 dbg!() prints the expression, file, and line — perfect for quick debugging
⚡ todo!() lets you leave unfinished code that compiles — panics if actually reached
📌 Macros use ! to distinguish them from functions — vec![], println!(), assert_eq!()
🟢 The hashmap!{} macro pattern is a common way to create utility macros for collections
macrosmacro-rulesattributes

File I/O

Read and write files with std::fs.

rust
💡 fs::read_to_string() and fs::write() are the quickest way to read/write files
⚡ Use BufReader for line-by-line reading — much more memory efficient than read_to_string
📌 All fs operations return Result — use ? to propagate errors
🟢 Use PathBuf::from("dir").join("file") for cross-platform path construction
filesiofspath

Modules & Cargo

Organize code with modules and manage dependencies with Cargo.

Modules & Visibility

Organize code into modules with pub/use and file-based structure.

rust
💡 Everything is private by default — add pub to make it accessible outside the module
⚡ pub(crate) makes something public within your crate but hidden from external users
📌 Module files: mod routes; looks for src/routes.rs or src/routes/mod.rs
🟢 Use pub use for re-exports — lets users import from a convenient path
modulesvisibilityusecargo

Testing

Write unit tests, integration tests, and use assert macros.

Writing Tests

Unit tests, integration tests, and test organization.

rust
💡 #[cfg(test)] ensures test code is never compiled into your release binary
⚡ Tests that return Result<(), E> let you use ? instead of .unwrap() — cleaner test code
📌 Use -- --nocapture to see println! output from passing tests
🟢 Integration tests go in tests/ directory and can only access your public API
testingassertunit-tests