πŸš€ Rust Introduction

Rust is a multi-paradigm, systems programming language focused on safety, speed, and concurrency. Originally developed at Mozilla Research by Graydon Hoare, Rust achieves memory safety without garbage collection through its unique ownership system and borrow checker. The language guarantees thread safety, prevents null pointer dereferencing, and eliminates data races at compile time.

Key Philosophy: "Zero-cost abstractions" - high-level features compile to efficient machine code with no runtime overhead. Rust combines C++-level performance with high-level language safety features. It's consistently voted "most loved programming language" in Stack Overflow surveys since 2016.

Compilation Model: Ahead-of-time compilation to native code via LLVM backend. Cargo package manager and build system. Rustup toolchain installer. Strong type system with type inference. Pattern matching, algebraic data types, and fearless concurrency.

Ecosystem: Crates.io repository with 100,000+ packages. Used by Microsoft, Google, Amazon, Facebook, Discord, Cloudflare, and Firefox. Powers critical infrastructure from operating systems (Redox OS) to blockchain (Solana) to web assembly.

// Rust 2021 Edition fn main() { println!("πŸ¦€ Rust Master Track - CodeOrbitPro"); // Immutable by default let name = "Ferris"; println!("Hello, {}!", name); // Mutable with explicit keyword let mut counter = 0; counter += 1; println!("Counter: {}", counter); // String vs &str let string_type = String::from("Heap allocated"); let string_slice = "Stack allocated"; println!("{} | {}", string_type, string_slice); }

πŸ“Š Variables & Ownership

Ownership is Rust's central feature ensuring memory safety without garbage collection. Three core rules: 1) Each value has a single owner, 2) When owner goes out of scope, value is dropped, 3) Values can be moved (transfer ownership) or borrowed (temporary reference).

Variable Binding: let x = 5; creates immutable binding. let mut y = 10; creates mutable binding. Variables are block-scoped. Shadowing allows redeclaration: let x = x + 1; creates new binding.

Move Semantics: For types not implementing Copy trait (like String, Vec), assignment moves ownership - original becomes invalid. Copy types (integers, bool, chars) are duplicated. Move prevents double-free errors.

Borrowing: References created with & (immutable borrow) or &mut (mutable borrow). Rules: 1) Any number of immutable borrows OR one mutable borrow, 2) References must always be valid (no dangling pointers). Borrow checker enforces these at compile time.

Ownership Patterns: Return ownership from functions, pass ownership to functions, use references for temporary access. Box<T> for heap allocation, Rc<T> for reference counting, Arc<T> for atomic reference counting.

fn main() { // Ownership example let s1 = String::from("hello"); let s2 = s1; // s1 is MOVED to s2, s1 becomes invalid // println!("{}", s1); // ERROR: borrow of moved value // Copy types (stack-only) let x = 5; let y = x; // COPY (not move), both valid println!("x={}, y={}", x, y); // Borrowing (references) let s3 = String::from("world"); let len = calculate_length(&s3); // Immutable borrow println!("Length of '{}': {}", s3, len); // Mutable borrowing let mut s4 = String::from("hello"); change_string(&mut s4); println!("Changed: {}", s4); // Multiple immutable borrows OK let r1 = &s4; let r2 = &s4; println!("{}, {}", r1, r2); // But mutable borrow exclusive // let r3 = &mut s4; // ERROR: cannot borrow s4 as mutable } fn calculate_length(s: &String) -> usize { s.len() } fn change_string(s: &mut String) { s.push_str(", world!"); }

🎭 Data Types

Scalar Types: Single-value types including integers (i8, i16, i32, i64, i128, isize), unsigned integers (u8-u128, usize), floating-point (f32, f64), boolean (bool), and character (char). Char is 4-byte Unicode scalar value. Integer literals support type suffixes: 42u8, 3.14f32.

Compound Types: Tuples group multiple types: (i32, f64, char). Access via pattern matching or .index. Arrays fixed-size, same type: [i32; 5]. Slices reference contiguous sequence: &[T].

String Types: String growable, heap-allocated UTF-8. &str string slice (immutable reference). String literals "hello" have type &'static str. Conversion: String::from(""), "".to_string(), "".to_owned().

Type Inference: Rust infers types using Hindley-Milner type system. Annotations required when ambiguous. let x: i32 = 5; explicit type. Turbofish syntax: Vec::<i32>::new().

Custom Types: Structs define custom data types. Enums define type that can be one of several variants. Both can have methods via impl blocks. Newtype pattern wraps existing type for type safety.

Never Type: ! represents computations that never return (diverging functions). Functions returning ! can be used where any type is expected. Used in panic!, loop without break.

fn main() { // Scalar types let integer: i32 = 42; let float: f64 = 3.14159; let boolean: bool = true; let character: char = 'πŸ¦€'; println!("Scalars: {}, {}, {}, {}", integer, float, boolean, character); // Compound types let tuple: (i32, f64, &str) = (500, 6.4, "hello"); let (x, y, z) = tuple; // Destructuring println!("Tuple: {}, {}, {}", x, y, tuple.2); let array: [i32; 5] = [1, 2, 3, 4, 5]; let slice: &[i32] = &array[1..4]; // [2, 3, 4] println!("Array: {:?}, Slice: {:?}", array, slice); // String types let string_literal: &str = "Hello"; let string_object: String = String::from("World"); let string_from_literal = "Converted".to_string(); println!("Strings: {}, {}, {}", string_literal, string_object, string_from_literal); // Type annotations let guessed = "42".parse::().expect("Not a number!"); println!("Parsed: {}", guessed); // Type aliases type Kilometers = i32; let distance: Kilometers = 100; println!("Distance: {}km", distance); }

πŸ”€ Control Flow

Conditionals: if expressions (not statements) evaluate to a value. Must have matching types in all arms. if let combines pattern matching with conditional execution. No ternary operator - use if/else expression.

Loops: Three loop types: loop (infinite, requires break), while (conditional), for (iterator-based). All loops are expressions that can return values via break value;. Loop labels for nested loops: 'outer: loop {}.

Pattern Matching: match is exhaustive pattern matching. Must cover all possibilities. Patterns can destructure tuples, structs, enums, references. Guards add extra conditions: Some(x) if x < 5 =>. _ wildcard matches anything.

Range Syntax: 1..5 (exclusive range), 1..=5 (inclusive range). Used in for loops and pattern matching. Ranges implement Iterator trait.

Flow Operators: break exits loop with optional value. continue skips to next iteration. return exits function early. ? operator propagates errors (shorthand for match on Result).

Control Flow as Expressions: Most constructs are expressions returning values. Blocks {} return last expression (no semicolon). if, match, loops can be assigned: let result = if condition { 1 } else { 0 };.

fn main() { // If expressions let number = 7; let description = if number % 2 == 0 { "even" } else { "odd" }; println!("{} is {}", number, description); // If let let some_value = Some(42); if let Some(x) = some_value { println!("Got value: {}", x); } // Match expression (exhaustive) let coin = Coin::Quarter(UsState::Alaska); let value = match coin { Coin::Penny => 1, Coin::Nickel => 5, Coin::Dime => 10, Coin::Quarter(state) => { println!("Quarter from {:?}!", state); 25 } }; println!("Coin value: {}", value); // Loops let mut counter = 0; let result = loop { counter += 1; if counter == 10 { break counter * 2; // Loop returns value } }; println!("Result: {}", result); // While loop let mut number = 3; while number != 0 { println!("{}!", number); number -= 1; } println!("LIFTOFF!"); // For loop with ranges for number in (1..4).rev() { println!("{}!", number); } println!("LIFTOFF again!"); // For loop with iterator let array = [10, 20, 30, 40, 50]; for element in array.iter() { println!("Value: {}", element); } } #[derive(Debug)] enum UsState { Alabama, Alaska, // ... others } enum Coin { Penny, Nickel, Dime, Quarter(UsState), }

βš™οΈ Functions

Function Definition: fn keyword_name(param: Type) -> ReturnType {}. Parameters require type annotations. Return type optional (defaults to () unit type). Last expression implicitly returned (no semicolon). Early return with return keyword.

Parameters & Arguments: Pass by value (moves or copies depending on type). Pass by reference with & or &mut. Function signatures must explicitly declare parameter types and lifetime annotations when needed.

Associated Functions: Functions defined in impl blocks. Self refers to implementing type. Constructor pattern: fn new() -> Self. Called with Type::function() syntax.

Methods: Functions with self parameter. &self for immutable reference, &mut self for mutable reference, self for ownership. Called with dot notation: instance.method().

Closures: Anonymous functions capturing environment. Three forms: |params| expr, |params| { statements; expr }, move |params| expr (takes ownership). Implement Fn, FnMut, or FnOnce traits.

Function Pointers: fn(i32) -> i32 type for functions. Can be stored in variables, passed as arguments. Different from closures (closures have unknown size at compile time).

Diverging Functions: Functions that never return have return type ! (never type). Used for functions that panic, loop forever, or exit process. Can be used where any type is expected.

fn main() { // Basic function let sum = add(5, 3); println!("5 + 3 = {}", sum); // Function with early return let result = early_return(10); println!("Early return: {}", result); // Expression vs statement let x = five(); // Function returning expression println!("Five: {}", x); // Methods let rect = Rectangle { width: 30, height: 50 }; println!("Area: {}", rect.area()); println!("Can hold 20x20? {}", rect.can_hold(&Rectangle { width: 20, height: 20 })); // Associated function (constructor) let square = Rectangle::square(25); println!("Square area: {}", square.area()); // Closures let closure = |x: i32| x * 2; println!("Closure: {}", closure(21)); let mut counter = 0; let mut increment = || { counter += 1; counter }; println!("Increment: {}", increment()); // Move closure let nums = vec![1, 2, 3]; let owns_nums = move || nums.len(); println!("Owns nums: {}", owns_nums()); // nums is moved, can't use here // Function pointers let func_ptr: fn(i32) -> i32 = add_one; println!("Function pointer: {}", func_ptr(5)); } // Basic function fn add(a: i32, b: i32) -> i32 { a + b // No semicolon = return expression } // Early return fn early_return(x: i32) -> i32 { if x < 0 { return 0; // Early return with keyword } x * 2 // Normal return } // Expression function fn five() -> i32 { 5 // Expression, no semicolon } // Struct and methods struct Rectangle { width: u32, height: u32, } impl Rectangle { // Method with &self fn area(&self) -> u32 { self.width * self.height } // Method with &mut self fn double(&mut self) { self.width *= 2; self.height *= 2; } // Method with self (takes ownership) fn max(self, other: Rectangle) -> Rectangle { if self.area() > other.area() { self } else { other } } // Associated function (no self) fn square(size: u32) -> Self { Rectangle { width: size, height: size } } // Method with parameter fn can_hold(&self, other: &Rectangle) -> bool { self.width > other.width && self.height > other.height } } // Function for function pointer fn add_one(x: i32) -> i32 { x + 1 }

πŸ—οΈ Structs & Enums

Structs: Custom data types grouping related data. Three variants: 1) Named-field structs (struct Point { x: i32, y: i32 }), 2) Tuple structs (struct Color(i32, i32, i32)), 3) Unit structs (struct Unit;). Field-level visibility with pub keyword.

Struct Updates: ..old_instance syntax copies remaining fields. Must come last in struct literal. Moves ownership of non-Copy fields. Useful for creating modified copies.

Enums: Type that can be one of several variants. Each variant can optionally contain data: enum Message { Quit, Move { x: i32, y: i32 }, Write(String), ChangeColor(i32, i32, i32) }. Enums are sized as largest variant + discriminant.

Option Enum: Option<T> represents optional value: Some(T) or None. Replaces null references. Must handle both cases via pattern matching. unwrap() extracts value or panics.

Result Enum: Result<T, E> represents success (Ok(T)) or failure (Err(E)). Used for error handling. ? operator propagates errors. Combinators: map(), and_then(), unwrap_or().

Pattern Matching: Destructure enums with match or if let. Exhaustive checking ensures all variants handled. @ binding captures value while matching: Message::Write(msg @ s) if s.starts_with("Hello") =>.

Derivable Traits: #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]. Debug for formatting, Clone for explicit copying, Copy for implicit copying, PartialEq/Eq for equality, Hash for hashing.

#[derive(Debug, Clone, PartialEq)] struct User { username: String, email: String, sign_in_count: u64, active: bool, } #[derive(Debug)] enum IpAddr { V4(u8, u8, u8, u8), V6(String), } #[derive(Debug)] enum Message { Quit, Move { x: i32, y: i32 }, Write(String), ChangeColor(i32, i32, i32), } impl Message { fn call(&self) { match self { Message::Quit => println!("Quit message"), Message::Move { x, y } => println!("Move to ({}, {})", x, y), Message::Write(text) => println!("Text message: {}", text), Message::ChangeColor(r, g, b) => println!("Change color to RGB({}, {}, {})", r, g, b), } } } fn main() { // Struct instantiation let user1 = User { email: String::from("someone@example.com"), username: String::from("someusername123"), active: true, sign_in_count: 1, }; // Struct update syntax let user2 = User { email: String::from("another@example.com"), username: String::from("anotherusername456"), ..user1 // Copies remaining fields from user1 }; println!("User1: {:?}", user1); println!("User2: {:?}", user2); // Tuple struct struct Color(i32, i32, i32); let black = Color(0, 0, 0); println!("Black: {:?}", black.0); // Access by index // Enums let home = IpAddr::V4(127, 0, 0, 1); let loopback = IpAddr::V6(String::from("::1")); println!("Home: {:?}, Loopback: {:?}", home, loopback); // Enum methods let m = Message::Write(String::from("hello")); m.call(); // Option enum let some_number = Some(5); let absent_number: Option = None; match some_number { Some(x) => println!("Got: {}", x), None => println!("Got nothing"), } // Option combinators let doubled = some_number.map(|x| x * 2); println!("Doubled: {:?}", doubled); // Result enum let result: Result = Ok(42); let error_result: Result = Err(String::from("Something went wrong")); match result { Ok(value) => println!("Success: {}", value), Err(e) => println!("Error: {}", e), } // ? operator (in function returning Result) let parsed = "42".parse::().map_err(|e| e.to_string())?; println!("Parsed: {}", parsed); } // This would need to return Result to use ? fn parse_example() -> Result { let parsed = "42".parse::().map_err(|e| e.to_string())?; Ok(parsed) }

πŸ“‹ Collections

Vector: Growable array Vec<T>. Heap-allocated, contiguous memory. Creation: Vec::new(), vec![] macro, Vec::with_capacity(n). Methods: push(), pop(), insert(), remove(), len(), capacity().

String: UTF-8 encoded, growable string. Actually a wrapper around Vec<u8>. Creation: String::new(), String::from(), to_string(), format!(). Methods: push_str(), push() (char), + operator (consumes left operand).

HashMap: Key-value store HashMap<K, V>. Hash function customizable via Hasher trait. Keys must implement Eq and Hash. Creation: HashMap::new(), HashMap::with_capacity(n). Methods: insert(), get(), entry() API.

HashSet: Unordered collection of unique values HashSet<T>. Implemented as HashMap with unit value. Methods: insert(), contains(), remove(), set operations: union(), intersection(), difference(), symmetric_difference().

Iteration: Collections implement IntoIterator. for item in &collection borrows, for item in collection consumes. Iterators: iter() (immutable refs), iter_mut() (mutable refs), into_iter() (ownership).

Ownership & Collections: Collections own their data. Storing references requires lifetime annotations. Vec<&T> stores references, Vec<T> stores owned values. clone() creates deep copies.

Other Collections: VecDeque double-ended queue, LinkedList doubly-linked list, BinaryHeap priority queue, BTreeMap/BTreeSet sorted maps/sets. std::collections module contains all.

use std::collections::{HashMap, HashSet}; fn main() { // Vector let mut v: Vec = Vec::new(); v.push(1); v.push(2); v.push(3); // Macro initialization let v2 = vec![1, 2, 3, 4, 5]; // Access elements let third: &i32 = &v[2]; println!("Third element: {}", third); // Safe access with get match v.get(2) { Some(third) => println!("Third element: {}", third), None => println!("No third element"), } // Iteration for i in &v { println!("{}", i); } // String let mut s = String::new(); s.push_str("hello"); s.push(' '); s.push_str("world"); let s2 = "rust".to_string(); let s3 = String::from("programming"); // Concatenation let combined = s + " " + &s2 + " " + &s3; println!("Combined: {}", combined); // Format macro (doesn't take ownership) let formatted = format!("{} {} {}", "Hello", "from", "Rust!"); println!("Formatted: {}", formatted); // Slicing strings (careful with char boundaries) let hello = "ЗдравствуйтС"; let slice = &hello[0..4]; // First two Cyrillic characters println!("Slice: {}", slice); // HashMap let mut scores = HashMap::new(); scores.insert(String::from("Blue"), 10); scores.insert(String::from("Yellow"), 50); // Access let team_name = String::from("Blue"); let score = scores.get(&team_name); println!("Blue score: {:?}", score); // Iterate for (key, value) in &scores { println!("{}: {}", key, value); } // Entry API scores.entry(String::from("Blue")).or_insert(100); scores.entry(String::from("Red")).or_insert(75); // Update value based on old let text = "hello world wonderful world"; let mut map = HashMap::new(); for word in text.split_whitespace() { let count = map.entry(word).or_insert(0); *count += 1; } println!("Word counts: {:?}", map); // HashSet let mut set = HashSet::new(); set.insert(1); set.insert(2); set.insert(3); set.insert(2); // Duplicate ignored println!("Set: {:?}", set); println!("Contains 2: {}", set.contains(&2)); // Set operations let set_a: HashSet<_> = [1, 2, 3].iter().cloned().collect(); let set_b: HashSet<_> = [2, 3, 4].iter().cloned().collect(); println!("Union: {:?}", set_a.union(&set_b).collect::>()); println!("Intersection: {:?}", set_a.intersection(&set_b).collect::>()); println!("Difference: {:?}", set_a.difference(&set_b).collect::>()); }

🎯 Traits

Traits define shared behavior across types. Similar to interfaces in other languages but more powerful. Declaration: trait TraitName { fn method(&self) -> ReturnType; }. Can provide default method implementations.

Trait Implementation: impl Trait for Type {}. Must implement all required methods (non-default). One type can implement many traits. One trait can be implemented for many types. Orphan rule: trait or type must be local to crate.

Trait Bounds: Generic constraints: fn func<T: Trait>(item: T) {}. Multiple bounds: T: Trait1 + Trait2. where clause for complex bounds: fn func<T, U>(t: T, u: U) where T: Trait1, U: Trait2 {}.

Trait Objects: Dynamic dispatch via &dyn Trait or Box<dyn Trait>. Enables heterogeneous collections. Sized trait requirement: trait objects are dynamically sized types (DSTs).

Associated Types: Placeholder types in trait definition: trait Iterator { type Item; fn next(&mut self) -> Option<Self::Item>; }. Each implementation specifies concrete type. Unlike generics, can only have one implementation per type.

Default Generic Type Parameters: trait Add<RHS=Self> { type Output; fn add(self, rhs: RHS) -> Self::Output; }. RHS defaults to Self if not specified.

Supertraits: Trait that requires another trait: trait Subtrait: Supertrait {}. Implementing type must also implement supertrait. Useful for trait inheritance.

Marker Traits: Traits with no methods, only semantics: Copy, Send, Sync. #[derive] automatically implements many marker traits.

Common Standard Traits: Debug (formatting), Display (user-facing), Clone/Copy (copying), PartialEq/Eq (equality), PartialOrd/Ord (ordering), Hash (hashing), Default (default values).

use std::fmt; // Basic trait trait Summary { fn summarize(&self) -> String; // Default implementation fn summarize_author(&self) -> String { String::from("(unknown author)") } // Default method using other methods fn summary_with_author(&self) -> String { format!("{} by {}", self.summarize(), self.summarize_author()) } } struct NewsArticle { headline: String, location: String, author: String, content: String, } impl Summary for NewsArticle { fn summarize(&self) -> String { format!("{}, by {} ({})", self.headline, self.author, self.location) } fn summarize_author(&self) -> String { self.author.clone() } } struct Tweet { username: String, content: String, reply: bool, retweet: bool, } impl Summary for Tweet { fn summarize(&self) -> String { format!("{}: {}", self.username, self.content) } } // Trait as parameter fn notify(item: &impl Summary) { println!("Breaking news! {}", item.summarize()); } // Trait bound syntax fn notify_generic(item: &T) { println!("Breaking news! {}", item.summarize()); } // Multiple trait bounds fn notify_multiple(item: &(impl Summary + fmt::Display)) { println!("Item: {}", item); println!("Summary: {}", item.summarize()); } // Where clause for complex bounds fn some_function(t: &T, u: &U) -> i32 where T: Summary + Clone, U: Clone + fmt::Debug, { 42 } // Returning traits (impl Trait) fn returns_summarizable() -> impl Summary { Tweet { username: String::from("horse_ebooks"), content: String::from("of course, as you probably already know, people"), reply: false, retweet: false, } } // Trait objects (dynamic dispatch) fn print_summary(items: &[&dyn Summary]) { for item in items { println!("Summary: {}", item.summarize()); } } // Associated types trait Container { type Item; fn add(&mut self, item: Self::Item); fn get(&self, index: usize) -> Option<&Self::Item>; } struct MyVec { items: Vec, } impl Container for MyVec { type Item = T; fn add(&mut self, item: T) { self.items.push(item); } fn get(&self, index: usize) -> Option<&T> { self.items.get(index) } } // Supertrait trait SuperTrait { fn super_method(&self); } trait SubTrait: SuperTrait { fn sub_method(&self); } struct MyType; impl SuperTrait for MyType { fn super_method(&self) { println!("Super method called"); } } impl SubTrait for MyType { fn sub_method(&self) { println!("Sub method called"); } } fn main() { let article = NewsArticle { headline: String::from("Rust reaches 1.0!"), location: String::from("San Francisco, CA"), author: String::from("Mozilla"), content: String::from("The Rust programming language has reached 1.0..."), }; let tweet = Tweet { username: String::from("rustlang"), content: String::from("Rust 1.70 released!"), reply: false, retweet: false, }; println!("Article: {}", article.summarize()); println!("Tweet: {}", tweet.summarize()); println!("Tweet with author: {}", tweet.summary_with_author()); notify(&article); notify_generic(&tweet); // Trait objects let items: Vec<&dyn Summary> = vec![&article, &tweet]; print_summary(&items); // Associated type usage let mut container = MyVec { items: Vec::new() }; container.add(42); container.add(100); println!("Got: {:?}", container.get(1)); // Supertrait usage let my_type = MyType; my_type.super_method(); my_type.sub_method(); }

⏳ Lifetimes

Lifetimes are compile-time constructs ensuring references are always valid. Every reference has a lifetime, usually inferred. Annotations required when relationships between references are ambiguous.

Lifetime Syntax: &'a T reference with lifetime 'a. Lifetime parameter names start with apostrophe: 'a, 'b, 'static. 'static lifetime lasts entire program duration (string literals, static variables).

Lifetime Elision: Compiler can infer lifetimes in common patterns: 1) Each reference parameter gets its own lifetime, 2) If exactly one input lifetime, it's assigned to all output lifetimes, 3) If &self or &mut self, output lifetime equals self lifetime.

Explicit Lifetime Annotations: Required when function returns reference(s) derived from input references. Syntax: fn longest<'a>(x: &'a str, y: &'a str) -> &'a str. Specifies that output lives as long as shortest input.

Struct Lifetimes: Structs containing references need lifetime annotations: struct Excerpt<'a> { part: &'a str }. Each struct instance can't outlive reference it holds. Lifetime on struct ensures references remain valid.

Lifetime Bounds: Generic type parameters can have lifetime bounds: T: 'a means all references in T must outlive 'a. T: 'static means T contains no references or only static references.

Multiple Lifetimes: Functions can have multiple lifetime parameters: fn foo<'a, 'b>(x: &'a str, y: &'b str) -> &'a str. Relationships between lifetimes: 'a: 'b means 'a outlives 'b.

Lifetime in Traits: Traits can have lifetime parameters: trait Trait<'a> {}. Associated types can have lifetime bounds: type Item: 'a;. HRTB (Higher-Rank Trait Bounds): for<'a> T: Trait<'a>.

Common Patterns: Returning reference to struct field, storing references in collections, implementing iterators, working with parser/combinator libraries. Understanding lifetimes is key to writing idiomatic Rust.

Lifetime vs Ownership: Lifetimes track reference validity, ownership tracks who can mutate/free data. Borrow checker uses both to guarantee safety. Dangling references impossible at compile time.

// Function requiring explicit lifetimes fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y } } // Struct with lifetime struct ImportantExcerpt<'a> { part: &'a str, } impl<'a> ImportantExcerpt<'a> { // Lifetime elision rule 3 applies fn announce_and_return_part(&self, announcement: &str) -> &str { println!("Attention! {}", announcement); self.part } // Multiple lifetimes fn longest_with_announcement<'b>(&self, announcement: &'b str) -> &'b str { println!("Announcement: {}", announcement); announcement } } // Lifetime bounds struct Ref<'a, T: 'a>(&'a T); // Multiple lifetime parameters with bounds fn choose_first<'a, 'b: 'a>(first: &'a str, second: &'b str) -> &'a str { first } // Static lifetime static HELLO_WORLD: &str = "Hello, world!"; fn returns_static() -> &'static str { "I live forever!" } // Lifetime in trait trait Processor<'a> { type Output; fn process(&self, input: &'a str) -> Self::Output; } struct StringProcessor; impl<'a> Processor<'a> for StringProcessor { type Output = String; fn process(&self, input: &'a str) -> String { input.to_uppercase() } } // HRTB (Higher-Rank Trait Bounds) fn call_on_ref_zero(f: F) where F: for<'a> Fn(&'a i32) { let value = 0; f(&value); } fn main() { let string1 = String::from("long string is long"); let string2 = "xyz"; let result = longest(string1.as_str(), string2); println!("The longest string is: {}", result); // Struct with lifetime let novel = String::from("Call me Ishmael. Some years ago..."); let first_sentence = novel.split('.').next().expect("Could not find a '.'"); let excerpt = ImportantExcerpt { part: first_sentence, }; println!("Excerpt: {}", excerpt.part); println!("Announcement: {}", excerpt.announce_and_return_part("Listen up!")); // Static lifetime let static_str: &'static str = returns_static(); println!("Static: {}", static_str); println!("Global: {}", HELLO_WORLD); // Nested scopes demonstrating lifetimes let result2; { let string3 = String::from("short"); let string4 = "really really long"; result2 = longest(string3.as_str(), string4); println!("The longest string is: {}", result2); } // string3 is dropped here, but result2 still valid because it references string4 // Lifetime bounds example let x = 5; let ref_x = Ref(&x); println!("Ref contains: {}", *ref_x.0); // Function with lifetime bounds let s1 = "hello"; let s2 = "world"; let chosen = choose_first(s1, s2); println!("Chosen: {}", chosen); // HRTB example call_on_ref_zero(|x| println!("Got: {}", x)); // Common mistake - won't compile /* let r; { let x = 5; r = &x; // ERROR: `x` does not live long enough } println!("r: {}", r); */ // Correct version let r; let x = 5; r = &x; println!("r: {}", r); }

πŸ›‘οΈ Error Handling

Result Type: Result<T, E> enum for recoverable errors. Ok(T) success variant, Err(E) error variant. Must handle both cases via pattern matching. Standard library functions return Result for operations that can fail.

Unwrap & Expect: unwrap() extracts value or panics on error. expect("message") panics with custom message. Use for prototyping or when error impossible. Production code should handle errors properly.

Propagating Errors: ? operator shorthand for match that returns error early. Can only be used in functions returning Result or Option. Converts error types using From trait. Cleaner than manual matching.

Error Conversion: Implement From trait for error type conversion. map_err() transforms error values. into() uses From trait for conversion. Third-party crates: anyhow for application errors, thiserror for library errors.

Custom Error Types: Create enums or structs implementing Error trait. Derive Debug and Display. Implement source() for error chaining. Use #[derive(thiserror::Error)] for convenience.

Option Type: Option<T> for optional values, not errors. Some(T) value present, None absent. Similar combinators to Result: map(), and_then(), unwrap_or().

Panic: panic!("message") for unrecoverable errors. Unwinding (default) or abort based on Cargo.toml settings. catch_unwind() catches panics (not for error handling). Use for bugs, not expected failures.

Error Combinators: map() transforms success value, map_err() transforms error, and_then() chains operations, or_else() handles errors, unwrap_or() provides default, unwrap_or_else() computes default.

Error Handling Patterns: Early return with ?, error wrapping with context, error conversion, error aggregation, result chaining. Match on specific error types. Use match for exhaustive handling.

Standard Error Traits: std::error::Error base trait with source() method. Display for user-facing messages. Debug for developer details. From for conversions.

use std::fs::File; use std::io::{self, Read}; use std::num::ParseIntError; use std::error::Error; // Custom error type #[derive(Debug)] enum MyError { Io(io::Error), Parse(ParseIntError), TooSmall(i32), Custom(String), } impl std::fmt::Display for MyError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { MyError::Io(e) => write!(f, "IO error: {}", e), MyError::Parse(e) => write!(f, "Parse error: {}", e), MyError::TooSmall(n) => write!(f, "Value {} is too small", n), MyError::Custom(msg) => write!(f, "Custom error: {}", msg), } } } impl std::error::Error for MyError { fn source(&self) -> Option<&(dyn Error + 'static)> { match self { MyError::Io(e) => Some(e), MyError::Parse(e) => Some(e), _ => None, } } } impl From for MyError { fn from(err: io::Error) -> MyError { MyError::Io(err) } } impl From for MyError { fn from(err: ParseIntError) -> MyError { MyError::Parse(err) } } // Function returning Result fn read_file_contents(filename: &str) -> Result { let mut file = File::open(filename)?; // ? converts io::Error to MyError let mut contents = String::new(); file.read_to_string(&mut contents)?; Ok(contents) } fn parse_number(s: &str) -> Result { let n: i32 = s.parse()?; // ? converts ParseIntError to MyError if n < 10 { Err(MyError::TooSmall(n)) } else { Ok(n) } } // Using combinators fn process_data(data: &str) -> Result { data.trim() .parse::() .map_err(MyError::from) // Convert error .and_then(|n| { if n > 100 { Ok(n * 2) } else { Err(MyError::Custom("Number too small".to_string())) } }) } // Option handling fn find_first_number(text: &str) -> Option { text.split_whitespace() .find_map(|word| word.parse::().ok()) } fn main() -> Result<(), MyError> { // Basic Result handling let result = parse_number("42"); match result { Ok(n) => println!("Parsed: {}", n), Err(e) => println!("Error: {}", e), } // Unwrap and expect let value = parse_number("100").unwrap(); // Panics on error println!("Unwrapped: {}", value); let value2 = parse_number("200").expect("Failed to parse"); println!("Expected: {}", value2); // Propagating errors with ? let contents = read_file_contents("example.txt")?; println!("File contents: {}", contents); // Combinators let processed = process_data("150").map(|n| n + 10); println!("Processed: {:?}", processed); // Option handling let text = "The answer is 42"; if let Some(number) = find_first_number(text) { println!("Found number: {}", number); } // Chain operations let final_result = parse_number("50") .map(|n| n * 3) .map_err(|e| MyError::Custom(format!("Modified: {}", e))); match final_result { Ok(n) => println!("Final: {}", n), Err(e) => println!("Final error: {}", e), } // Error context (simulated) let sensitive_operation = || -> Result<(), MyError> { // Simulate operation that might fail if rand::random() { Ok(()) } else { Err(MyError::Custom("Random failure".to_string())) } }; match sensitive_operation() { Ok(_) => println!("Operation succeeded"), Err(e) => { println!("Operation failed: {}", e); if let Some(source) = e.source() { println!("Caused by: {}", source); } } } // Panic example (uncomment to see) // panic!("This is a panic!"); Ok(()) }

⚑ Concurrency

Threads: OS threads via std::thread::spawn(). Returns JoinHandle. join() waits for thread completion. Threads capture environment via move closures. Thread local storage with thread_local! macro.

Message Passing: "Do not communicate by sharing memory; share memory by communicating." Channels from std::sync::mpsc (multiple producer, single consumer). Sender and Receiver halves. Send any type implementing Send trait.

Mutex: Mutual exclusion via Mutex<T>. lock() returns MutexGuard implementing Deref and Drop. Poisoned mutex detection. RwLock for multiple readers or single writer.

Arc: Atomic reference counting (Arc<T>) for shared ownership across threads. Similar to Rc but thread-safe. Clone increments reference count. Data must implement Send and Sync.

Send & Sync Traits: Marker traits for thread safety. Send: type can be transferred between threads. Sync: type can be shared between threads via references. Most types are Send and Sync automatically.

Atomic Types: std::sync::atomic provides atomic operations: AtomicBool, AtomicUsize, AtomicPtr. Operations: load(), store(), fetch_add(), compare_exchange(). Memory ordering: Relaxed, Acquire, Release, AcqRel, SeqCst.

Async/Await: Asynchronous programming with async/await. Non-blocking I/O managed by runtime (tokio, async-std). Futures are lazy, poll-based. .await yields control until future ready.

Concurrent Patterns: Worker thread pools, parallel iterators (Rayon), data parallelism, pipeline patterns, fan-out/fan-in, barriers, condition variables. Crates: rayon for data parallelism, crossbeam for advanced concurrency.

Deadlock Prevention: Lock ordering, timeout locks, try_lock, deadlock detection. Rust prevents data races but not deadlocks. Use try_lock() for non-blocking attempts.

Shared-State Concurrency: Combine Arc<Mutex<T>> for shared mutable state. Arc enables sharing, Mutex ensures exclusive access. Pattern: clone Arc, move into thread, lock when needed.

use std::thread; use std::sync::{Arc, Mutex, mpsc}; use std::time::Duration; use std::sync::atomic::{AtomicUsize, Ordering}; fn main() { // Basic thread let handle = thread::spawn(|| { for i in 1..10 { println!("hi number {} from the spawned thread!", i); thread::sleep(Duration::from_millis(1)); } }); for i in 1..5 { println!("hi number {} from the main thread!", i); thread::sleep(Duration::from_millis(1)); } handle.join().unwrap(); // Move closure let v = vec![1, 2, 3]; let handle = thread::spawn(move || { println!("Here's a vector: {:?}", v); // v is moved into thread }); handle.join().unwrap(); // Message passing with channels let (tx, rx) = mpsc::channel(); let tx1 = tx.clone(); // Clone sender for second thread thread::spawn(move || { let vals = vec![ String::from("hi"), String::from("from"), String::from("the"), String::from("thread"), ]; for val in vals { tx1.send(val).unwrap(); thread::sleep(Duration::from_millis(100)); } }); thread::spawn(move || { let vals = vec![ String::from("more"), String::from("messages"), String::from("for"), String::from("you"), ]; for val in vals { tx.send(val).unwrap(); thread::sleep(Duration::from_millis(150)); } }); // Receive messages for received in rx { println!("Got: {}", received); } // Shared state with Arc and Mutex let counter = Arc::new(Mutex::new(0)); let mut handles = vec![]; for _ in 0..10 { let counter = Arc::clone(&counter); let handle = thread::spawn(move || { let mut num = counter.lock().unwrap(); *num += 1; }); handles.push(handle); } for handle in handles { handle.join().unwrap(); } println!("Result: {}", *counter.lock().unwrap()); // Atomic operations let atomic_counter = Arc::new(AtomicUsize::new(0)); let mut atomic_handles = vec![]; for _ in 0..10 { let counter = Arc::clone(&atomic_counter); let handle = thread::spawn(move || { for _ in 0..1000 { counter.fetch_add(1, Ordering::SeqCst); } }); atomic_handles.push(handle); } for handle in atomic_handles { handle.join().unwrap(); } println!("Atomic result: {}", atomic_counter.load(Ordering::SeqCst)); // RwLock for multiple readers use std::sync::RwLock; let lock = RwLock::new(5); // Many readers { let r1 = lock.read().unwrap(); let r2 = lock.read().unwrap(); println!("Readers: {}, {}", r1, r2); } // Read locks dropped here // One writer { let mut w = lock.write().unwrap(); *w += 1; println!("After write: {}", w); } // Barrier synchronization use std::sync::Barrier; let barrier = Arc::new(Barrier::new(3)); let mut barrier_handles = vec![]; for i in 0..3 { let barrier = Arc::clone(&barrier); let handle = thread::spawn(move || { println!("Thread {} before barrier", i); barrier.wait(); println!("Thread {} after barrier", i); }); barrier_handles.push(handle); } for handle in barrier_handles { handle.join().unwrap(); } // Thread local storage thread_local! { static THREAD_ID: std::cell::Cell = std::cell::Cell::new(0); } THREAD_ID.with(|id| { id.set(42); println!("Thread local value: {}", id.get()); }); }

✨ Macros

Declarative Macros: Pattern-based code generation with macro_rules!. Match against code patterns, generate code. Hygienic - identifiers won't conflict. Used for DSLs, repetitive code, variadic functions.

Procedural Macros: Functions that operate on token streams. Three types: 1) Custom derive (#[derive(MyMacro)]), 2) Attribute-like (#[my_macro]), 3) Function-like (my_macro!()). Defined in separate crates with proc-macro = true.

Macro Patterns: Matchers: $x:expr (expression), $i:ident (identifier), $t:ty (type), $l:literal (literal), $($x:expr),* (repetition). Designators specify what code fragment to capture.

Repetition: $(...)* zero or more, $(...)+ one or more, $(...)? zero or one. Can have separators: $(...),*. Generate repetitive code like implementing traits for multiple types.

Hygiene: Macros don't accidentally capture identifiers from calling scope. $crate metavariable refers to crate where macro defined. Local variables must be passed explicitly.

Built-in Macros: println!(), format!(), vec![], assert!(), panic!(), include!(), concat!(), env!(), option_env!(). Compile-time evaluation.

Attribute Macros: #[my_attribute] applied to items. Receive token stream of annotated item. Can modify, replace, or generate new items. Common for web frameworks, serialization, testing.

Function-like Macros: my_macro!(...) look like function calls but operate on tokens. More flexible than declarative macros. Used in libraries like lazy_static!, tokio::main.

Macro Development: Use proc-macro2 and syn for parsing, quote for code generation. Debug with cargo expand. Procedural macros execute at compile time.

Common Use Cases: Derive macros for traits, builders, DSLs, compile-time validation, code generation, reducing boilerplate, implementing patterns for multiple types.

// Declarative macro macro_rules! say_hello { () => { println!("Hello!"); }; } macro_rules! create_function { ($func_name:ident) => { fn $func_name() { println!("You called {:?}()", stringify!($func_name)); } }; } macro_rules! print_result { ($expression:expr) => { println!("{:?} = {:?}", stringify!($expression), $expression); }; } macro_rules! vec_strings { ($($element:expr),*) => {{ let mut v = Vec::new(); $(v.push($element.to_string());)* v }}; } macro_rules! find_min { ($x:expr) => ($x); ($x:expr, $($y:expr),+) => ( std::cmp::min($x, find_min!($($y),+)) ); } // Using macros create_function!(foo); create_function!(bar); fn main() { // Simple macro say_hello!(); // Generated functions foo(); bar(); // Expression macro print_result!(1u32 + 1); print_result!({ let x = 1u32; x * x + 2 * x - 1 }); // Repetition macro let strings = vec_strings!("hello", "world", "rust"); println!("Vector: {:?}", strings); // Recursive macro let min = find_min!(1, 5, 3, 10, 2); println!("Minimum: {}", min); // Built-in macros let formatted = format!("Hello, {}!", "world"); println!("{}", formatted); let v = vec![1, 2, 3, 4, 5]; println!("Vector: {:?}", v); // Assertion macro assert!(2 + 2 == 4); assert_eq!(2 + 2, 4); assert_ne!(2 + 2, 5); // Compile-time environment let home = env!("HOME"); println!("Home directory: {}", home); // Concatenation let concatenated = concat!("Hello", " ", "World", "!"); println!("{}", concatenated); // Include file contents // let config = include_str!("config.toml"); // More complex macro pattern macro_rules! calculate { (eval $e:expr) => {{ let val: usize = $e; println!("{} = {}", stringify!($e), val); }}; (eval $e:expr, $(eval $es:expr),+) => {{ calculate!(eval $e); calculate!($(eval $es),+); }}; } calculate! { eval 1 + 2, eval 3 + 4, eval (2 * 3) + 1 } // Macro for implementing traits macro_rules! impl_debug_for_point { ($type:ty) => { impl std::fmt::Debug for $type { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "Point({}, {})", self.x, self.y) } } }; } struct Point { x: i32, y: i32 } impl_debug_for_point!(Point); let p = Point { x: 5, y: 10 }; println!("Point: {:?}", p); // Hygiene example macro_rules! hygienic { () => { let temp = 42; println!("Temp: {}", temp); }; } hygienic!(); // temp is not accessible here - hygienic! // Macro with different patterns macro_rules! test { ($left:expr; and $right:expr) => { println!("{:?} and {:?} is {:?}", stringify!($left), stringify!($right), $left && $right) }; ($left:expr; or $right:expr) => { println!("{:?} or {:?} is {:?}", stringify!($left), stringify!($right), $left || $right) }; } test!(true; and false); test!(true; or false); }

πŸ“¦ Modules & Packages

Packages: Cargo package contains Cargo.toml file defining metadata and dependencies. Can contain multiple binary crates and at most one library crate. Built with cargo build, tested with cargo test, documented with cargo doc.

Crates: Compilation unit - library or binary. Library crates don't have main() function, define functionality for other crates. Binary crates compile to executables. Crate root is source file Rust compiler starts from (src/lib.rs or src/main.rs).

Modules: Organize code within crate. Declared with mod keyword. Can be nested. Module tree reflects filesystem structure. Items are private by default, exposed with pub keyword.

Visibility: pub makes item public. pub(crate) visible within crate. pub(in path::to::module) visible in specific module path. pub(super) visible to parent module. pub(self) same as private.

Paths: Ways to name items. Absolute paths start with crate name or crate::. Relative paths start with self::, super::, or identifier. Use use to bring paths into scope.

Use Declarations: use creates shortcuts to items. Can be re-exported with pub use. Idiomatic to bring parent module, not items directly. Group imports with nested paths: use std::{cmp::Ordering, io};.

File Separation: Modules can be in separate files. mod garden; declaration tells Rust to look in garden.rs or garden/mod.rs. Directory modules have mod.rs file. 2018 edition prefers filename matching module name.

Workspaces: Multiple packages sharing Cargo.lock and output directory. Defined in Cargo.toml workspace section. Useful for large projects with multiple crates. Each crate can be published separately.

Dependencies: Specified in Cargo.toml [dependencies] section. Version ranges: 1.0.0 (exact), ^1.0.0 (compatible), ~1.0.0 (patch updates), =1.0.0 (exact), 1.* (any 1.x). Features enable optional functionality.

Common Patterns: Library with public API, binary that uses library, examples in examples/, tests in tests/ directory, benchmarks in benches/. Documentation comments with /// for items, //! for crate/module docs.

// This would be in separate files in a real project // For demonstration, showing module structure // Crate root (src/lib.rs or src/main.rs) mod front_of_house { pub mod hosting { pub fn add_to_waitlist() { println!("Added to waitlist"); } fn seat_at_table() { println!("Seated at table"); } } mod serving { fn take_order() { println!("Order taken"); } fn serve_order() { println!("Order served"); } fn take_payment() { println!("Payment taken"); } } } // Using the module pub fn eat_at_restaurant() { // Absolute path crate::front_of_house::hosting::add_to_waitlist(); // Relative path front_of_house::hosting::add_to_waitlist(); } // Re-exporting pub use crate::front_of_house::hosting; // Nested modules in separate files would be: // src/front_of_house.rs // src/front_of_house/hosting.rs // Example of module in separate file simulation mod back_of_house { pub struct Breakfast { pub toast: String, seasonal_fruit: String, } impl Breakfast { pub fn summer(toast: &str) -> Breakfast { Breakfast { toast: String::from(toast), seasonal_fruit: String::from("peaches"), } } } pub enum Appetizer { Soup, Salad, } fn fix_incorrect_order() { cook_order(); super::deliver_order(); // super refers to parent module } fn cook_order() {} } fn deliver_order() {} // Using the struct with private fields pub fn order_breakfast() { let mut meal = back_of_house::Breakfast::summer("Rye"); meal.toast = String::from("Wheat"); println!("I'd like {} toast please", meal.toast); // Cannot access private field // meal.seasonal_fruit = String::from("blueberries"); } // Using the enum (all variants public if enum is public) pub fn choose_appetizer() { let order1 = back_of_house::Appetizer::Soup; let order2 = back_of_house::Appetizer::Salad; } // Use declarations use std::collections::HashMap; use std::fmt::Result; use std::io::Result as IoResult; // Aliasing fn function1() -> Result { Ok(()) } fn function2() -> IoResult<()> { Ok(()) } // Nested paths use std::{cmp::Ordering, io}; use std::io::{self, Write}; // self includes std::io too // Glob operator use std::collections::*; // Main function demonstrating everything fn main() { eat_at_restaurant(); order_breakfast(); choose_appetizer(); // Using re-exported module hosting::add_to_waitlist(); // Using imported items let mut map = HashMap::new(); map.insert("key", "value"); // Workspace example (conceptual) // Cargo.toml would have: /* [workspace] members = [ "crate1", "crate2", "crate3", ] */ // Dependency example (conceptual) // Cargo.toml would have: /* [dependencies] serde = { version = "1.0", features = ["derive"] } tokio = { version = "1.0", features = ["full"] } */ println!("Module system demonstration complete!"); } // Tests module #[cfg(test)] mod tests { use super::*; #[test] fn test_add_to_waitlist() { // Can test public functions front_of_house::hosting::add_to_waitlist(); assert!(true); } // Integration tests would be in tests/ directory } // Examples directory (conceptual) // examples/simple_example.rs would be: /* use my_crate::hosting; fn main() { hosting::add_to_waitlist(); } */

πŸ”₯ Advanced Rust

Unsafe Rust: Five unsafe superpowers: 1) Dereference raw pointers, 2) Call unsafe functions, 3) Implement unsafe traits, 4) Access or modify mutable static variables, 5) Access union fields. Marked with unsafe keyword. Use sparingly and encapsulate in safe abstractions.

Raw Pointers: *const T immutable raw pointer, *mut T mutable raw pointer. No guarantees about validity, no automatic cleanup, can be null, ignore borrowing rules. Convert references with & as *const or &mut as *mut.

FFI (Foreign Function Interface): Call C code from Rust with extern "C". Define foreign functions with extern block. Use libc crate for C types. #[no_mangle] prevents name mangling. C calling conventions: "C", "stdcall", "fastcall".

Inline Assembly: asm! macro for architecture-specific assembly. Feature-gated (#![feature(asm)]). Specify inputs, outputs, clobbers. Volatile operations. Platform-specific constraints.

const Generics: Generic over constant values: struct Array<T, const N: usize> { data: [T; N] }. Enables type-level integers. Used for fixed-size arrays, bit sets, matrix dimensions. Compile-time evaluation of constants.

Associated Type Constructors (ATC): Generic associated types (GATs) enable associated types to have generics. trait Iterable { type Iter<'a>; fn iter(&self) -> Self::Iter<'_>; }. Stabilized in Rust 1.65.

Specialization: Overriding default trait implementations with more specific ones. default keyword marks implementations that can be specialized. Currently unstable (#![feature(specialization)]).

Pin: Pin<P> guarantees that pointee cannot be moved. Used for self-referential structs, async/await state machines. Unpin trait indicates type can be safely moved out of Pin.

Type-level Programming: Using type system to enforce invariants at compile time. Phantom types, typestate pattern, singleton types. Crates: typenum for type-level numbers, frunk for generic programming.

Advanced Patterns: Newtype pattern for type safety, builder pattern for complex construction, interior mutability patterns (Cell, RefCell, Mutex), RAII for resource management, iterator adapters, custom allocators.

// Unsafe Rust example unsafe fn dangerous() { println!("Doing something dangerous!"); } // Raw pointers fn raw_pointers_example() { let mut num = 5; let r1 = &num as *const i32; let r2 = &mut num as *mut i32; unsafe { println!("r1 is: {}", *r1); println!("r2 is: {}", *r2); *r2 = 10; println!("After mutation: {}", *r1); } // Creating raw pointers from arbitrary addresses let address = 0x012345usize; let r = address as *const i32; // unsafe { println!("Value at address: {}", *r); } // Would likely segfault } // Calling unsafe function fn unsafe_calls() { unsafe { dangerous(); } } // Unsafe trait unsafe trait DangerousTrait { fn do_something(&self); } unsafe impl DangerousTrait for i32 { fn do_something(&self) { println!("i32 doing something dangerous: {}", self); } } // FFI example (would need linking to C library) extern "C" { fn abs(input: i32) -> i32; } fn call_c_function() { unsafe { println!("Absolute value of -3 according to C: {}", abs(-3)); } } // Static mutable variable (unsafe to access) static mut COUNTER: u32 = 0; fn increment_counter() { unsafe { COUNTER += 1; } } // Union (unsafe to access) union MyUnion { f1: u32, f2: f32, } // const generics struct Array { data: [T; N], } impl Array { fn new() -> Self { Array { data: [T::default(); N], } } fn len(&self) -> usize { N } } // Advanced type patterns struct Meter(f64); struct Kilometer(f64); impl Meter { fn to_kilometers(&self) -> Kilometer { Kilometer(self.0 / 1000.0) } } // Newtype pattern struct UserId(u64); struct ProductId(u64); // Builder pattern #[derive(Debug)] struct Connection { url: String, timeout: u32, retries: u32, } struct ConnectionBuilder { url: Option, timeout: Option, retries: Option, } impl ConnectionBuilder { fn new() -> Self { ConnectionBuilder { url: None, timeout: None, retries: None, } } fn url(mut self, url: &str) -> Self { self.url = Some(url.to_string()); self } fn timeout(mut self, timeout: u32) -> Self { self.timeout = Some(timeout); self } fn retries(mut self, retries: u32) -> Self { self.retries = Some(retries); self } fn build(self) -> Result { Ok(Connection { url: self.url.ok_or("URL must be set")?, timeout: self.timeout.unwrap_or(30), retries: self.retries.unwrap_or(3), }) } } // Interior mutability use std::cell::{Cell, RefCell}; fn interior_mutability_example() { // Cell for Copy types let cell = Cell::new(42); cell.set(100); println!("Cell value: {}", cell.get()); // RefCell for non-Copy types let refcell = RefCell::new(String::from("hello")); { let mut borrowed = refcell.borrow_mut(); borrowed.push_str(" world"); } println!("RefCell value: {}", refcell.borrow()); } // RAII pattern struct FileGuard { filename: String, } impl FileGuard { fn new(filename: &str) -> Result { println!("Opening file: {}", filename); Ok(FileGuard { filename: filename.to_string(), }) } fn read(&self) -> String { format!("Reading from {}", self.filename) } } impl Drop for FileGuard { fn drop(&mut self) { println!("Closing file: {}", self.filename); } } // Advanced iterator usage fn advanced_iterators() { let numbers = vec![1, 2, 3, 4, 5]; // Iterator chain let result: Vec<_> = numbers .iter() .map(|x| x * 2) .filter(|x| x > &5) .collect(); println!("Filtered: {:?}", result); // Fold let sum = numbers.iter().fold(0, |acc, x| acc + x); println!("Sum: {}", sum); // Scan let running_totals: Vec<_> = numbers.iter().scan(0, |state, &x| { *state += x; Some(*state) }).collect(); println!("Running totals: {:?}", running_totals); } fn main() { // Unsafe examples raw_pointers_example(); unsafe_calls(); let num = 42; unsafe { num.do_something(); } call_c_function(); increment_counter(); increment_counter(); unsafe { println!("Counter: {}", COUNTER); } // Union usage let u = MyUnion { f1: 42 }; unsafe { println!("Union field: {}", u.f1); } // const generics let arr: Array = Array::new(); println!("Array length: {}", arr.len()); // Type-safe units let distance = Meter(1000.0); let in_km = distance.to_kilometers(); // Builder pattern let connection = ConnectionBuilder::new() .url("http://example.com") .timeout(60) .retries(5) .build() .unwrap(); println!("Connection: {:?}", connection); // Interior mutability interior_mutability_example(); // RAII { let file = FileGuard::new("test.txt").unwrap(); println!("{}", file.read()); } // File automatically closed here // Advanced iterators advanced_iterators(); // Specialized patterns println!("Advanced Rust features demonstrated!"); }