Create Project with Cargo

  1. What Is Cargo?



  2. Check If Cargo Is Installed
  3. $ cargo --version
    cargo 1.80.0 (or similar)
    



  4. Create a New Binary Project
  5. $ cargo new hello-rust
         Created binary (application) `hello-rust` package
    

    $ cd hello-rust
    


  6. Project Layout (Created by Cargo)
  7. hello-rust/
    ├── Cargo.toml
    └── src
        └── main.rs
    



  8. Inspecting src/main.rs
  9. fn main() {
        println!("Hello, world!");
    }
    



  10. Inspecting Cargo.toml
  11. [package]
    name = "hello-rust"
    version = "0.1.0"
    edition = "2021"
    
    [dependencies]
    



  12. Build the Project
  13. $ cargo build
       Compiling hello-rust v0.1.0 (path/to/hello-rust)
        Finished dev [unoptimized + debuginfo] target(s) in 0.50s
    

    $ ls target/debug
    hello-rust   # executable
    


  14. Run the Project
  15. $ cargo run
       Compiling hello-rust v0.1.0 (path/to/hello-rust)
        Finished dev [unoptimized + debuginfo] target(s) in 0.50s
         Running `target/debug/hello-rust`
    Hello, world!
    

    $ cargo run -- --help
    


  16. Create a Library Project
  17. $ cargo new my-lib --lib
         Created library `my-lib` package
    

    my-lib/
    ├── Cargo.toml
    └── src
        └── lib.rs
    



  18. Use cargo init in an Existing Directory
  19. $ mkdir existing-project
    $ cd existing-project
    $ cargo init
         Created binary (application) `existing-project` package
    



  20. Debug vs Release Builds
  21. # Debug build (default)
    $ cargo build
    
    # Release build (optimized, slower compile)
    $ cargo build --release
    



  22. Add Dependencies to Your Project
  23. [dependencies]
    rand = "0.8"
    

    use rand::Rng;
    
    fn main() {
        let mut rng = rand::thread_rng();
        let n: u8 = rng.gen_range(0..=9);
        println!("Random number: {n}");
    }
    



  24. Useful Cargo Commands for a New Project

  25. Command Description
    cargo new <name> Create a new project directory with Cargo files
    cargo init Initialize Cargo in the current directory
    cargo build Compile the project (debug mode)
    cargo run Build and run the binary
    cargo check Type-check without producing binaries (faster feedback)
    cargo test Run tests (if any exist in tests/ or src)
    cargo clean Remove the target/ directory





Comments in Rust

  1. Introduction



  2. Line Comments (//)
  3. // This is a single-line comment
    let x = 10; // you can also put comments at the end of a line
    



  4. Block Comments (/* ... */)
  5. /*
       This is a block comment.
       It can span multiple lines.
    */
    let x = 5;
    

    /*
        Outer comment
        /*
            Nested comment — valid!
        */
    */
    



  6. Documentation Comments (/// and //! )


  7. Documentation for Functions (///)
  8. /// Adds two numbers together.
    ///
    /// # Examples
    /// ```
    /// let sum = add(2, 3);
    /// assert_eq!(sum, 5);
    /// ```
    fn add(a: i32, b: i32) -> i32 {
        a + b
    }
    



  9. Documentation for Modules or Crates (//! )
  10. //! This is documentation for the entire module or crate.
    //! It describes the purpose and structure at a high level.
    
    //! You typically put this at the top of `lib.rs` or inside a module.
    



  11. Inner vs Outer Documentation Comments

  12. Kind Syntax Applies To
    Outer doc /// Item that follows
    Inner doc //! Enclosing module or crate


  13. Doc Comments Support Markdown
  14. /// # Title
    /// - Bullet point
    /// - Another
    ///
    /// `inline code`
    ///
    /// ```rust
    /// let x = 5;
    /// println!("{}", x);
    /// ```
    fn demo() {}
    



  15. Generate Docs and Open Them
  16. $ cargo doc --open
    



  17. Temporary Disabling Code with Block Comments
  18. /*
    fn calculate() {
        // temporarily disabled
    }
    */
    

    /*
    fn a() {}
    
    /*
    fn b() {}
    */
    
    fn c() {}
    */
    



  19. Choosing the Right Comment Style

  20. Use Case Style Example
    Explain a line of code // // explanation
    Explain a block or disable code /* ... */ /* long comment */
    Document a function/struct/enum /// /// Adds two numbers
    Document a module/crate //! //! Top-level docs




Formatted Print

  1. Introduction



  2. Basic Printing
  3. fn main() {
        println!("Hello, world!");
        print!("No newline here");
    }
    



  4. Printing with Placeholder {}
  5. fn main() {
        let name = "Alice";
        let age = 30;
    
        println!("Name: {}, Age: {}", name, age);
    }
    



  6. Debug Formatting ({:?})
  7. #[derive(Debug)]
    struct User {
        id: u32,
        name: String,
    }
    
    fn main() {
        let u = User { id: 1, name: "Alice".into() };
        println!("{:?}", u);
    }
    

    println!("{:#?}", u);  // pretty debug
    


  8. Named Arguments
  9. println!("x = {x}, y = {y}", x = 5, y = 10);
    



  10. Positional Arguments
  11. println!("{0} + {0} = {1}", 5, 10);
    



  12. Formatting Numbers
  13. println!("{:b}", 10);   // binary
    println!("{:o}", 10);   // octal
    println!("{:x}", 255);  // hex (lower)
    println!("{:X}", 255);  // hex (upper)
    println!("{:e}", 10.5); // scientific
    



  14. Padding and Alignment
  15. println!("{:>10}", 42);   // right-align
    println!("{:<10}", 42);   // left-align
    println!("{:^10}", 42);   // center-align
    



  16. Custom Fill Characters
  17. println!("{:*^10}", "hi");   // ****hi****
    println!("{:-<10}", "rust"); // rust------
    



  18. Floating-Point Precision
  19. println!("{:.2}", 3.14159);   // 3.14
    println!("{:8.3}", 3.14159);  // '   3.142' (width + precision)
    



  20. Format Strings with format!
  21. let msg = format!("Hello, {}", "world");
    println!("{}", msg);
    



  22. Printing to stderr (eprintln!)
  23. eprintln!("This is an error message.");
    



  24. Implementing Display for Custom Types
  25. use std::fmt;
    
    struct Point {
        x: i32,
        y: i32,
    }
    
    impl fmt::Display for Point {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            write!(f, "({}, {})", self.x, self.y)
        }
    }
    
    fn main() {
        let p = Point { x: 3, y: 4 };
        println!("{}", p);
    }
    



  26. Useful Escape Sequences
  27. println!("Line 1\nLine 2");
    println!("Tab\tSeparated");
    println!("Quote: \"text\"");
    println!("Backslash: \\");
    



  28. Raw Strings (No Escaping)
  29. println!(r"Path: C:\Users\Alice\Documents");
    println!(r#"He said, "Hello!""#);
    println!(r##"Multiple # signs can be used"##);
    



  30. Format Specifier Summary

  31. Specifier Description Example
    {} Display "{}"
    {:?} Debug "{:?}"
    {:#?} Pretty Debug "{:#?}"
    {:b} Binary 10 → 1010
    {:x} Hex (lowercase) 255 → ff
    {:X} Hex (uppercase) 255 → FF
    {:o} Octal 10 → 12
    {:.N} Floating precision 3.14
    {:width} Minimum field width "{:5}"
    {:<} Left align "{:<10}"
    {:>} Right align "{:>10}"
    {:^} Center align "{:^10}"





Primitives in Rust

  1. Rust provides a set of primitive types (built-in types) that form the foundation of all Rust programs.

  2. Primitives are:

  3. Primitive categories include:


  4. Integer Types
  5. let a: i32 = 10;    // signed 32-bit integer
    let b: u64 = 20;    // unsigned 64-bit integer
    let c = 100usize;   // machine pointer-sized unsigned integer
    



  6. Number Literals
  7. let dec = 98_222;
    let hex = 0xff;
    let oct = 0o77;
    let bin = 0b1111_0000;
    let byte = b'A'; // u8 only
    



  8. Floating-Point Types
  9. let x = 3.14f32;    // 32-bit float
    let y: f64 = 2.718; // 64-bit float (default)
    



  10. Boolean
  11. let is_active: bool = true;
    let is_valid = false;
    



  12. Character (Unicode Scalar Value)
  13. let a = 'A';
    let heart = '❤';
    let chinese = '中';
    let emoji = '🚀';
    



  14. Tuples
  15. let tup: (i32, f64, bool) = (10, 3.14, true);
    
    let (x, y, z) = tup;  // destructuring
    
    println!("y = {}", tup.1);
    



  16. Arrays
  17. let nums: [i32; 3] = [1, 2, 3];
    let zeros = [0; 5]; // [0, 0, 0, 0, 0]
    



  18. Slices
  19. let arr = [1, 2, 3, 4];
    let slice: &[i32] = &arr[1..3];  // [2, 3]
    



  20. String Slices
  21. let s: &str = "Hello";      // string slice
    let part = &s[0..2];        // slice bytes, careful with UTF-8
    



  22. Owned String (String)
  23. let mut s = String::from("Hello");
    s.push_str(" World");
    



  24. Special Primitive: Unit (())
  25. fn do_something() {
        // returns () implicitly
    }
    



  26. Special Primitive: Never (!)
  27. fn fail() -> ! {
        panic!("Something went wrong");
    }
    



  28. Primitive Type Summary

  29. Category Type Description
    Integer i*, u* Signed/unsigned integers
    Float f32, f64 Floating-point numbers
    Boolean bool true, false
    Character char Unicode scalar value
    Tuple (T1, T2, ...) Fixed-size heterogeneous values
    Array [T; N] Fixed-size homogeneous values
    Slice &[T] View into contiguous memory
    String Slice &str UTF-8 string reference
    Owned String String Growable heap string
    Unit () No meaningful value
    Never ! Function never returns





Structs

  1. In Rust, a struct is a custom data type that groups related values together.

  2. Structs are similar to classes in other languages but without inheritance.

  3. Rust provides several types of structs:


  4. Classic Structs (Named Fields)
  5. struct User {
        id: u32,
        name: String,
        active: bool,
    }
    
    fn main() {
        let u = User {
            id: 1,
            name: String::from("Alice"),
            active: true,
        };
    
        println!("Name: {}", u.name);
    }
    



  6. Mutable Struct Instances
  7. let mut user = User {
        id: 1,
        name: String::from("Alice"),
        active: true,
    };
    
    user.name = String::from("Bob");
    



  8. Field Init Shorthand
  9. let id = 1;
    let name = String::from("Alice");
    
    let user = User {
        id,
        name,
        active: true,
    };
    



  10. Struct Update Syntax
  11. let user1 = User {
        id: 1,
        name: String::from("Alice"),
        active: true,
    };
    
    let user2 = User {
        name: String::from("Bob"),
        ..user1
    };
    



  12. Tuple Structs
  13. struct Color(u8, u8, u8);
    struct Point(f64, f64);
    
    fn main() {
        let c = Color(255, 0, 128);
        let p = Point(10.5, 3.2);
    
        println!("Red = {}", c.0);
    }
    



  14. Unit-Like Structs
  15. struct Marker;
    
    fn main() {
        let m = Marker;
    }
    



  16. Implementing Methods for Structs
  17. struct Rectangle {
        width: u32,
        height: u32,
    }
    
    impl Rectangle {
        fn area(&self) -> u32 {
            self.width * self.height
        }
    }
    
    fn main() {
        let rect = Rectangle { width: 10, height: 20 };
        println!("Area: {}", rect.area());
    }
    



  18. Mutable Methods
  19. impl Rectangle {
        fn double_size(&mut self) {
            self.width *= 2;
            self.height *= 2;
        }
    }
    



  20. Associated Functions (Static Methods)
  21. impl Rectangle {
        fn new(width: u32, height: u32) -> Self {
            Self { width, height }
        }
    }
    
    let rect = Rectangle::new(5, 10);
    



  22. Debug Printing with #[derive(Debug)]
  23. #[derive(Debug)]
    struct User {
        id: u32,
        name: String,
    }
    
    fn main() {
        let u = User { id: 1, name: "Alice".into() };
        println!("{:?}", u);
        println!("{:#?}", u); // pretty-print
    }
    



  24. Ownership and Structs
  25. struct User {
        name: String,
    }
    
    let u1 = User { name: String::from("Alice") };
    let u2 = u1;                // move occurs
    // println!("{}", u1.name); // ERROR: moved
    



  26. Struct Summary

  27. Struct Type Description Example
    Classic Named fields struct User { id: u32 }
    Tuple Unnamed fields struct Point(i32, i32)
    Unit-like No fields struct Marker;
    With methods Use impl for methods impl User { fn new() {} }





Enums

  1. Rust's enum (short for *enumeration*) is one of its most powerful and expressive features.

  2. Enums allow you to define a type that can be one of several variants.

  3. Unlike enums in languages like C, Rust enums can store data inside each variant.

  4. Combined with match, enums enable expressive and type-safe control flow.


  5. Basic Enum
  6. enum Direction {
        Up,
        Down,
        Left,
        Right,
    }
    
    fn main() {
        let d = Direction::Up;
    }
    



  7. Enums with Data
  8. enum Message {
        Quit,                    // no data
        Move { x: i32, y: i32 }, // named fields
        Write(String),           // tuple-like
        ChangeColor(u8, u8, u8), // tuple-like with multiple values
    }
    



  9. Using Enums with match
  10. fn process(msg: Message) {
        match msg {
            Message::Quit           => println!("Quit"),
            Message::Move { x, y }  => println!("Move to ({}, {})", x, y),
            Message::Write(text)    => println!("Text: {}", text),
            Message::ChangeColor(r, g, b) =>
                println!("Color change: ({}, {}, {})", r, g, b),
        }
    }
    



  11. Enum with Methods
  12. enum Shape {
        Circle(f64),
        Rectangle { w: f64, h: f64 },
    }
    
    impl Shape {
        fn area(&self) -> f64 {
            match self {
                Shape::Circle(r)          => std::f64::consts::PI * r * r,
                Shape::Rectangle { w, h } => w * h,
            }
        }
    }
    
    fn main() {
        let c = Shape::Circle(3.0);
        println!("Area: {}", c.area());
    }
    



  13. The Option<T> Enum
  14. enum Option<T> {
        Some(T),
        None,
    }
    
    let x: Option<i32> = Some(10);
    let y: Option<i32> = None;
    



  15. Matching on Option
  16. fn print_number(n: Option<i32>) {
        match n {
            Some(value) => println!("Value = {}", value),
            None        => println!("No value"),
        }
    }
    



  17. if let for Convenience
  18. let n = Some(10);
    
    if let Some(value) = n {
        println!("Value = {}", value);
    }
    



  19. The Result<T, E> Enum
  20. enum Result<T, E> {
        Ok(T),
        Err(E),
    }
    
    fn divide(a: f64, b: f64) -> Result<f64, String> {
        if b == 0.0 {
            Err(String::from("Divide by zero"))
        } else {
            Ok(a / b)
        }
    }
    



  21. C-like Enums (Discriminants)
  22. enum Status {
        Ready = 1,
        Busy  = 2,
        Error = 3,
    }
    
    let x = Status::Busy as i32;
    



  23. Enums with #[derive]
  24. #[derive(Debug, Clone, Copy)]
    enum Direction {
        Up,
        Down,
        Left,
        Right,
    }
    



  25. Enum Summary

  26. Enum Feature Description Example
    Unit Variant No data Quit
    Tuple Variant Unnamed fields Write(String)
    Struct Variant Named fields Move { x: i32, y: i32 }
    Methods on Enums Via impl block fn area(&self)
    Option<T> Nullable alternative Some(10), None
    Result<T, E> Error handling Ok(x), Err(e)





Constants in Rust

  1. Introduction



  2. Defining a const Value
  3. const MAX_POINTS: u32 = 100_000;
    const PI: f64 = 3.141_592_653_589;
    



  4. Constants vs let Variables
  5. const MAX_USERS: u32 = 1_000;
    
    fn main() {
        let current_users = 10;    // runtime variable
        println!("Current: {}, max: {}", current_users, MAX_USERS);
    }
    



  6. Scope of Constants
  7. const GLOBAL_LIMIT: u32 = 10_000;
    
    fn main() {
        const LOCAL_FACTOR: u32 = 2;
        println!("Global = {}, local = {}", GLOBAL_LIMIT, LOCAL_FACTOR);
    }
    



  8. Constants in Types and Array Sizes
  9. const ROWS: usize = 3;
    const COLS: usize = 4;
    
    fn main() {
        let matrix: [[i32; COLS]; ROWS] = [[0; COLS]; ROWS];
        println!("Matrix has {} rows and {} cols", ROWS, COLS);
    }
    



  10. static Variables (Global Storage)
  11. static APP_NAME: &str = "My Rust App";
    static MAX_CONNECTIONS: u32 = 1024;
    



  12. static mut and Safety
  13. static mut COUNTER: u32 = 0;
    
    fn main() {
        unsafe {
            COUNTER += 1;
            println!("COUNTER = {}", COUNTER);
        }
    }
    



  14. Using static with Interior Mutability
  15. use std::sync::Mutex;
    
    static COUNTER: Mutex<u32> = Mutex::new(0);
    
    fn main() {
        let mut n = COUNTER.lock().unwrap();
        *n += 1;
        println!("COUNTER = {}", *n);
    }
    



  16. const fn and Computed Constants
  17. const fn square(x: i32) -> i32 {
        x * x
    }
    
    const FOUR: i32 = square(2);
    const SIXTEEN: i32 = square(4);
    



  18. Summary: const vs static vs let

  19. Keyword When Evaluated Storage Mutability Typical Use
    let Runtime Stack (or moved to heap inside types) Immutable by default, can be mut Normal variables, function-local state
    const Compile time Inlined, no single fixed address Always immutable Global configuration, array sizes, generic parameters
    static Compile-time initialization Single fixed memory location Immutable by default, static mut is unsafe Global data with 'static lifetime





Variable Bindings

  1. Introduction



  2. Basic Immutable Binding
  3. let x = 10;
    println!("x = {}", x);
    



  4. Mutable Binding
  5. let mut count = 0;
    count += 1;
    println!("count = {}", count);
    



  6. Type Annotations
  7. let x: i32 = 42;
    let name: &str = "Alice";
    



  8. Shadowing
  9. let x = 5;
    let x = x + 1;   // shadows the previous x
    {
        let x = x * 2;
        println!("x inside block = {}", x); // 12
    }
    println!("x outside block = {}", x);     // 6
    



  10. Destructuring Bindings
  11. let (a, b, c) = (1, 2, 3);
    println!("a = {}, b = {}, c = {}", a, b, c);
    

    struct Point { x: i32, y: i32 }
    
    let p = Point { x: 10, y: 20 };
    let Point { x, y } = p;
    println!("x = {}, y = {}", x, y);
    

    let (x, _) = (10, 99);
    


  12. Binding by Reference
  13. let x     = 10;
    let ref_x = &x;
    
    println!("ref_x = {}", ref_x);
    



  14. Mutable References as Bindings
  15. let mut x = 10;
    let y     = &mut x;
    *y += 5;
    println!("x = {}", x);
    



  16. Binding with match Patterns
  17. let numbers = vec![1, 2, 3];
    
    match numbers.as_slice() {
        [first, .., last] => println!("first = {}, last = {}", first, last),
        _                 => println!("Too short"),
    }
    


  18. Using let in if and while let
  19. if let Some(n) = Some(5) {
        println!("n = {}", n);
    }
    
    let mut v = vec![1, 2, 3];
    
    while let Some(n) = v.pop() {
        println!("popped {}", n);
    }
    



  20. Freezing via Immutable Binding
  21. let mut x = 10;
    let y     = &x;
    
    println!("y = {}", y);
    
    // x += 1; // ERROR: x frozen while y exists
    



  22. Summary of Variable Binding Rules

  23. Binding Feature Description Example
    Immutable by default Cannot change value let x = 5;
    Mutable binding Explicit mut required let mut x = 5;
    Shadowing Create new binding with same name let x = x + 1;
    Pattern binding Destructure tuples, structs, enums let (a, b) = pair;
    Move semantics Non-Copy values move on assignment let t = s;
    Binding references Store & or &mut let r = &x;




Types

  1. Introduction



  2. Type Inference
  3. let x    = 10;          // inferred as i32
    let name = "Alice";     // inferred as &str
    


  4. Annotating Types Explicitly
  5. let x: i64 = 100;
    let flag: bool = true;
    let scores: [i32; 3] = [10, 20, 30];
    



  6. Type Aliases
  7. type Kilometers = i32;
    
    let distance: Kilometers = 50;
    

    type Result<T> = std::result::Result<T, String>;
    


  8. Primitive Types (Built-in)



  9. Compound Types
  10. let tup: (i32, &str) = (10, "Hi");
    let arr: [u8; 4] = [1, 2, 3, 4];
    



  11. User-Defined Types
  12. struct User {
        id: u32,
        name: String,
    }
    
    enum Direction {
        Up,
        Down,
        Left,
        Right,
    }
    
    type Id = u64;
    


  13. Reference Types
  14. let x = 10;
    let r1: &i32 = &x;
    
    let mut y = 20;
    let r2: &mut i32 = &mut y;
    



  15. Function Types
  16. fn add(a: i32, b: i32) -> i32 {
        a + b
    }
    



  17. Closure Types
  18. let add = |x: i32, y: i32| x + y;
    println!("{}", add(2, 3));
    



  19. Generic Types
  20. struct Point<T> {
        x: T,
        y: T,
    }
    
    let p = Point { x: 1.0, y: 2.0 };
    



  21. Trait Object Types (dyn Trait)
  22. trait Speak {
        fn speak(&self);
    }
    
    struct Dog;
    impl Speak for Dog {
        fn speak(&self) { println!("Woof"); }
    }
    
    let animal: &dyn Speak = &Dog;
    animal.speak();
    



  23. Never Type (!)
  24. fn crash() -> ! {
        panic!("boom");
    }
    



  25. Type Coercions
  26. let s: &str = "Hello";
    let slice: &[u8] = s.as_bytes();
    



  27. Summary of Rust Type Categories

  28. Category Description Examples
    Primitive Built-in low-level types i32, bool, char, &str
    User-defined Custom structs, enums, aliases struct User, enum Option
    Reference Borrows without ownership &T, &mut T
    Function / Closure Callable values fn(i32)->i32, Fn closures
    Generic Parameterized types Vec<T>, Option<T>
    Trait objects Dynamic dispatch dyn Write, dyn Display




Conversion

  1. Introduction



  2. Casting with as
  3. let a = 10_i32;
    let b = a as i64;       // widen
    let c = 300_u16 as u8;  // truncate
    let d = 3.14_f32 as i32;
    



  4. The From Trait (Preferred for Safe Conversions)
  5. let s = String::from("hello");
    let v = Vec::from([1, 2, 3]);
    let n = i32::from(42_u8);
    



  6. The Into Trait (Auto-Implemented from From)
  7. fn greet(name: impl Into<String>) {
        let s: String = name.into();
        println!("Hello {}", s);
    }
    
    greet("Alice");              // &str   → String
    greet(String::from("Bob"));  // String → String
    



  8. Fallible Conversions: TryFrom and TryInto
  9. use std::convert::TryFrom;
    
    let x: u8  = 200;
    let result = i8::try_from(x);
    
    match result {
        Ok(n)  => println!("n = {}", n),
        Err(e) => println!("Error: {}", e),
    }
    
    use std::convert::TryInto;
    
    let val: i16 = (-5).try_into().unwrap(); // will panic!
    




  10. String Conversions

  11. A. To String
    let n  = 123;
    let s1 = n.to_string();
    let s2 = format!("Number: {}", n);
    let s3: String = "hello".into();
    



    B. From String (Parsing)
    let s = "42";
    let n: i32 = s.parse().unwrap();
    



    C. String Slice <-> String
    let s: &str = "hello";
    let owned: String = s.to_string();
    
    let another: &str = &owned;    // &String → &str
    




  12. Reference Conversions: AsRef and AsMut
  13. fn print_bytes(input: T) {
        let bytes = input.as_ref();
        println!("{:?}", bytes);
    }
    
    print_bytes("hello");            // &str → &[u8]
    print_bytes(String::from("hi")); // String → &[u8]
    



  14. Pointer Conversions (Unsafe)
  15. let x = 10;
    let ptr = &x as *const i32;
    let addr = ptr as usize;
    



  16. Enum Discriminant Conversions
  17. #[repr(u8)]
    enum Status {
        Ok    = 1,
        Error = 2,
    }
    
    let x = Status::Ok as u8;
    



  18. Custom Conversion Implementations
  19. struct Point {
        x: i32,
        y: i32,
    }
    
    impl From<(i32, i32)> for Point {
        fn from(t: (i32, i32)) -> Self {
            Point { x: t.0, y: t.1 }
        }
    }
    
    let p = Point::from((3, 4));
    



  20. Summary of Rust Conversion Mechanisms

  21. Mechanism Description Fallible? Example
    as Primitive casts, sometimes unsafe No (may truncate) x as u8
    From Idiomatic, guaranteed success No String::from(&str)
    Into Auto-implemented reciprocal of From No let s: String = str.into()
    TryFrom Checked conversions Yes i8::try_from(200)
    TryInto Auto-implemented reciprocal of TryFrom Yes (-5).try_into()
    parse() String parsing via FromStr Yes "42".parse()
    AsRef Cheap reference conversion No path.as_ref()
    AsMut Mutable reference conversion No buf.as_mut()





if / else

  1. Introduction



  2. Basic if
  3. let x = 10;
    
    if x > 5 {
        println!("x is greater than 5");
    }
    



  4. if / else
  5. let x = 3;
    
    if x % 2 == 0 {
        println!("even");
    } else {
        println!("odd");
    }
    



  6. else if (Chained Conditions)
  7. let score = 85;
    
    if score >= 90 {
        println!("A");
    } else if score >= 80 {
        println!("B");
    } else if score >= 70 {
        println!("C");
    } else {
        println!("D");
    }
    



  8. if as an Expression
  9. let x = 5;
    
    let result = if x > 3 {
        "big"
    } else {
        "small"
    };
    
    println!("result = {}", result);
    



  10. Mismatched Types in Branches (Error)
  11. let x = 5;
    
    let result = if x > 3 {
        10        // i32
    } else {
        "small"   // &str
    };
    



  12. Using if in let bindings
  13. let temperature = 30;
    
    let advice = if temperature > 25 {
        "Wear light clothes"
    } else {
        "Wear a jacket"
    };
    
    println!("{}", advice);
    



  14. Nested if
  15. let x = 15;
    
    if x > 10 {
        if x < 20 {
            println!("x is between 10 and 20");
        }
    }
    



  16. Returning Complex Values from if
  17. struct User {
        name: String,
        admin: bool,
    }
    
    let user = User { name: "Alice".into(), admin: false };
    
    let label = if user.admin {
        format!("Admin: {}", user.name)
    } else {
        format!("User: {}", user.name)
    };
    
    println!("{}", label);
    



  18. Using if with Option values
  19. let value: Option<i32> = Some(10);
    
    if let Some(v) = value {
        println!("We got {}", v);
    } else {
        println!("No value");
    }
    



  20. if let for Ignoring the Else Branch
  21. let maybe_number = Some(5);
    
    if let Some(x) = maybe_number {
        println!("Got {}", x);
    }
    // else is optional
    



  22. Short-Circuiting with Boolean Expressions
  23. let logged_in = true;
    let is_admin = false;
    
    if logged_in && is_admin {
        println!("Welcome, admin");
    } else {
        println!("Access denied");
    }
    



  24. if vs match
  25. let x = 5;
    
    match x {
        0 => println!("Zero"),
        1..=5 => println!("Small"),
        _ => println!("Large"),
    }
    



  26. Summary of if / else

  27. Feature Description Example
    Basic if Executes block when condition is true if x > 0 { ... }
    if / else Fallback branch when condition is false if a { ... } else { ... }
    else if Multiple branching conditions else if x > 10
    Expression Returns a value let v = if cond { 1 } else { 2 };
    Type consistency Both branches must match i32 / i32, not mixed
    if let Pattern matching convenience if let Some(v) = opt





loop

  1. Introduction



  2. Basic loop
  3. let mut count = 0;
    
    loop {
        println!("count = {}", count);
        count += 1;
    
        if count == 3 {
            break;
        }
    }
    



  4. Using break to exit the loop
  5. let mut n = 1;
    
    loop {
        if n > 5 {
            break;
        }
        println!("{}", n);
        n += 1;
    }
    



  6. loop is an expression (can return a value)
  7. let mut x = 0;
    
    let result = loop {
        x += 1;
    
        if x == 5 {
            break x * 2; // break with value
        }
    };
    
    println!("result = {}", result);
    



  8. Using continue
  9. for i in 1..=5 {
        if i % 2 == 0 {
            continue;
        }
        println!("{}", i);
    }
    



  10. Loop Labels (controlling nested loops)
  11. 'outer: loop {
        println!("In outer loop");
    
        loop {
            println!("In inner loop");
            break 'outer; // exit BOTH loops
        }
    }
    
    
    
    let result = 'outer: loop {
        println!("In outer loop");
    
        loop {
            println!("In inner loop");
            break 'outer 42; // exit BOTH loops with value 42
        }
    };
    println!("result = {result}");
    



  12. Loop with return
  13. fn find() -> i32 {
        let mut n = 0;
    
        loop {
            if n == 7 {
                return n; // exit the function entirely
            }
            n += 1;
        }
    }
    



  14. Infinite loops intentionally
  15. loop {
        println!("This runs forever");
    }
    


  16. Combining loop with state transitions
  17. let mut state = 0;
    
    loop {
        match state {
            0 => {
                println!("Start");
                state = 1;
            }
            1 => {
                println!("Processing");
                state = 2;
            }
            2 => {
                println!("Done");
                break;
            }
            _ => unreachable!(),
        }
    }
    


  18. Using loop to retry operations
  19. use std::fs::File;
    
    loop {
        match File::open("config.txt") {
            Ok(f) => {
                println!("File opened");
                break;
            }
            Err(_) => {
                println!("Retrying...");
            }
        }
    }
    


  20. Summary of loop

  21. Feature Description Example
    Basic loop Repeats forever loop { ... }
    Break Stops the loop break;
    Break with value Returns value from loop-expression break x;
    Continue Skip to next iteration continue;
    Loop labels Control nested loops 'label: loop { ... }
    State machines Ideal for multi-step logic match state { ... }





while

  1. Introduction



  2. Basic while loop
  3. let mut n = 1;
    
    while n <= 5 {
        println!("{}", n);
        n += 1;
    }
    



  4. Using break in a while loop
  5. let mut x = 0;
    
    while x < 10 {
        if x == 4 {
            break; // stop the loop early
        }
        println!("{}", x);
        x += 1;
    }
    



  6. Using continue in while
  7. let mut x = 0;
    
    while x < 5 {
        x += 1;
    
        if x % 2 == 0 {
            continue; // skip even numbers
        }
    
        println!("{}", x);
    }
    



  8. Countdown example
  9. let mut count = 3;
    
    while count > 0 {
        println!("{}", count);
        count -= 1;
    }
    
    println!("Lift off!");
    



  10. while with conditions that change inside the loop
  11. let mut temperature = 20;
    
    while temperature < 25 {
        println!("Heating... {}", temperature);
        temperature += 1;
    }
    



  12. while as an alternative to some for loops
  13. let arr = [10, 20, 30, 40];
    let mut i = 0;
    
    while i < arr.len() {
        println!("{}", arr[i]);
        i += 1;
    }
    



  14. while let (pattern-based iteration)
  15. let mut opt = Some(3);
    
    while let Some(x) = opt {
        println!("{}", x);
        opt = if x > 1 { Some(x - 1) } else { None };
    }
    



  16. Using while let with collections
  17. let mut stack = vec![1, 2, 3];
    
    while let Some(top) = stack.pop() {
        println!("Popped: {}", top);
    }
    



  18. Labelled while loops
  19. 'outer: while true {
        let mut x = 0;
    
        while x < 5 {
            if x == 2 {
                break 'outer; // exit the outer loop
            }
            x += 1;
        }
    }
    



  20. Infinite while loop (not recommended)
  21. while true {
        println!("Running...");
    }
    



  22. while for waiting on conditions
  23. let mut ready = false;
    
    while !ready {
        println!("Waiting...");
        // check some condition...
        ready = true; // simulate becoming ready
    }
    
    println!("Ready!");
    





for and Range

  1. Introduction



  2. Basic for loop with a range
  3. for i in 0..5 {
        println!("{}", i);
    }
    



  4. Inclusive range
  5. for i in 0..=5 {
        println!("{}", i);
    }
    



  6. Reverse iteration using rev()
  7. for i in (1..5).rev() {
        println!("{}", i);
    }
    



  8. Iterating over an array
  9. let arr = [10, 20, 30];
    
    for value in arr {
        println!("{}", value);
    }
    



  10. Iterating over a vector by reference
  11. let v = vec![10, 20, 30];
    
    for value in &v {
        println!("{}", value);
    }
    



  12. Mutable iteration over a vector
  13. let mut v = vec![1, 2, 3];
    
    for value in &mut v {
        *value *= 2;
    }
    
    println!("{:?}", v);
    



  14. Enumerating index and value
  15. let arr = ["a", "b", "c"];
    
    for (index, value) in arr.iter().enumerate() {
        println!("{}: {}", index, value);
    }
    



  16. Iterating over characters in a string
  17. let s = "Hello";
    
    for c in s.chars() {
        println!("{}", c);
    }
    



  18. Iterating over bytes in a string
  19. let s = "Hello";
    
    for b in s.bytes() {
        println!("{}", b);
    }
    



  20. Using for with patterns
  21. let pairs = vec![(1, 2), (3, 4)];
    
    for (a, b) in pairs {
        println!("{} + {} = {}", a, b, a + b);
    }
    



  22. Looping multiple ranges (Cartesian product)
  23. for x in 0..3 {
        for y in 0..3 {
            println!("({}, {})", x, y);
        }
    }
    



  24. Breaking from a for loop
  25. for i in 0..10 {
        if i == 4 {
            break;
        }
        println!("{}", i);
    }
    



  26. Continuing to next iteration
  27. for i in 0..10 {
        if i % 2 == 0 {
            continue; // skip even numbers
        }
        println!("{}", i);
    }
    



  28. Labelled for loops
  29. 'outer: for x in 0..3 {
        for y in 0..3 {
            if x == 1 && y == 1 {
                break 'outer;
            }
            println!("({}, {})", x, y);
        }
    }
    



  30. Range types: from and to
  31. // exclusive end
    let r1 = 1..5;   // 1,2,3,4
    
    // inclusive end
    let r2 = 1..=5;  // 1,2,3,4,5
    



  32. Ranges used in slices
  33. let arr = [10, 20, 30, 40, 50];
    
    let slice = &arr[1..4];  // elements 1 through 3
    println!("{:?}", slice);
    



  34. Summary of for and range

  35. Feature Description Example
    Exclusive range End value is excluded 0..5
    Inclusive range End value included 0..=5
    Reverse iteration Iterate backwards (1..5).rev()
    Vector iteration Borrow or move elements for v in &vec
    Enumerate Index + value .enumerate()
    Characters Iterate Unicode chars s.chars()
    Pattern matching Destructure in loop head for (a,b) in pairs
    Labels Control nested loops 'outer: for...





match

  1. Introduction



  2. Basic match
  3. let n = 3;
    
    match n {
        1 => println!("one"),
        2 => println!("two"),
        3 => println!("three"),
        _ => println!("something else"),
    }
    



  4. match is an expression
  5. let n = 5;
    
    let description = match n {
        1 => "one",
        2 => "two",
        3 => "three",
        _ => "other",
    };
    
    println!("{}", description);
    



  6. Matching ranges
  7. let age = 20;
    
    match age {
        0..=12  => println!("child"),
        13..=19 => println!("teenager"),
        _       => println!("adult"),
    }
    



  8. Multiple patterns with |
  9. let c = 'a';
    
    match c {
        'a' | 'e' | 'i' | 'o' | 'u' => println!("vowel"),
        _ => println!("consonant or other"),
    }
    



  10. Matching Option<T>
  11. let x: Option<i32> = Some(10);
    
    match x {
        Some(n) => println!("value = {}", n),
        None    => println!("no value"),
    }
    



  12. Matching Result<T, E>
  13. let r: Result<i32, &str> = Ok(42);
    
    match r {
        Ok(v)  => println!("Success: {}", v),
        Err(e) => println!("Error: {}", e),
    }
    



  14. Binding matched values
  15. let n = 7;
    
    match n {
        1 => println!("one"),
        2 => println!("two"),
        other => println!("something else: {}", other),
    }
    



  16. Pattern guards
  17. let n = 10;
    
    match n {
        x if x % 2 == 0 => println!("even"),
        _ => println!("odd"),
    }
    



  18. Destructuring tuples
  19. let pair = (3, -3);
    
    match pair {
        (0, y) => println!("x is zero, y = {}", y),
        (x, 0) => println!("y is zero, x = {}", x),
        (x, y) => println!("x = {}, y = {}", x, y),
    }
    



  20. Destructuring structs
  21. struct Point { x: i32, y: i32 }
    
    let p = Point { x: 3, y: 7 };
    
    match p {
        Point { x: 0, y } => println!("on y-axis at {}", y),
        Point { x, y: 0 } => println!("on x-axis at {}", x),
        Point { x, y }     => println!("({}, {})", x, y),
    }
    



  22. Match an enum with data
  23. enum Message {
        Quit,
        Move { x: i32, y: i32 },
        Write(String),
    }
    
    let msg = Message::Move { x: 3, y: 5 };
    
    match msg {
        Message::Quit => println!("Quit"),
        Message::Move { x, y } => println!("Move to ({}, {})", x, y),
        Message::Write(text) => println!("Message: {}", text),
    }
    



  24. Matching references
  25. let x = 5;
    
    match &x {
        &1 => println!("one"),
        &n => println!("something else: {}", n),
    }
    



  26. Ignoring parts of a pattern
  27. let pair = (10, 20);
    
    match pair {
        (x, _) => println!("first = {}", x),
    }
    



  28. Deep destructuring
  29. let data = (Some(3), 10);
    
    match data {
        (Some(x), y) => println!("x = {}, y = {}", x, y),
        (None, y)    => println!("no x, y = {}", y),
    }
    



  30. Match with return values
  31. let n = 10;
    
    let result = match n {
        0 => "zero",
        1 => "one",
        _ => "many",
    };
    
    println!("{}", result);
    



  32. Summary of match

  33. Feature Description Example
    Basic matching Compare values to patterns match x { 1 => ... }
    Wildcard Catches all unmatched cases _ => ...
    Ranges Match inclusive ranges 0..=10
    Multiple patterns OR conditions 'a' | 'b'
    Enums Destructure and match variants Message::Move { x, y }
    Guards Apply extra conditions x if x % 2 == 0
    Bindings Store matched value n => ...
    Destructuring Break apart structs/tuples (x, y)
    Expressions Return values from match let t = match x { ... }




if let

  1. Introduction



  2. Basic if let with Option<T>
  3. let value: Option<i32> = Some(10);
    
    if let Some(v) = value {
        println!("Value is {}", v);
    }
    



  4. if let ... else
  5. let value: Option<i32> = None;
    
    if let Some(v) = value {
        println!("Value = {}", v);
    } else {
        println!("No value found");
    }
    



  6. if let is a shortcut for match
  7. let value = Some(5);
    
    match value {
        Some(v) => println!("{}", v),
        _ => {},
    }
    
    if let Some(v) = value {
        println!("{}", v);
    }
    



  8. Matching Result<T, E>
  9. let result: Result<i32, &str> = Ok(42);
    
    if let Ok(n) = result {
        println!("Number is {}", n);
    }
    



  10. Using if let with enums
  11. enum Msg {
        Quit,
        Move { x: i32, y: i32 },
    }
    
    let m = Msg::Move { x: 3, y: 7 };
    
    if let Msg::Move { x, y } = m {
        println!("Moving to ({}, {})", x, y);
    }
    



  12. if let with pattern guards
  13. let n = Some(12);
    
    if let Some(v) = n if v > 10 {
        println!("Large number: {}", v);
    }
    



  14. Mutably binding with if let
  15. let mut opt = Some(5);
    
    if let Some(ref mut v) = opt {
        *v += 1;
    }
    
    println!("{:?}", opt);
    



  16. if let with references
  17. let x = Some(10);
    
    if let Some(&v) = x.as_ref() {
        println!("v = {}", v);
    }
    



  18. Combining multiple patterns (nested)
  19. let data = Some((1, 2));
    
    if let Some((a, b)) = data {
        println!("a = {}, b = {}", a, b);
    }
    



  20. if let chains (Rust 1.65+)
  21. let a = Some(10);
    let b = Some(20);
    
    if let Some(x) = a
        && let Some(y) = b
    {
        println!("Both present: {} and {}", x, y);
    }
    





let else

  1. Introduction

  2. let PATTERN = EXPR else {
        HANDLING_CODE
    };



  3. Basic let else Example
  4. let Some(value) = maybe_value else {
        println!("No value!");
        return;
    };
    
    println!("Got: {}", value);
    



  5. Why let else? Cleaner than match
  6. // Traditional match:
    let value = match maybe_value {
        Some(v) => v,
        None => return,
    };
    
    // Cleaner with let else:
    let Some(value) = maybe_value else {
        return;
    };
    



  7. Using let else with multiple variables
  8. let Ok((x, y)) = do_work() else {
        eprintln!("Work failed");
        return;
    };
    
    println!("x = {}, y = {}", x, y);
    



  9. let else in loops
  10. while let Some(line) = lines.next() {
        let Ok(num) = line.parse::<i32>() else {
            continue; // skip malformed input
        };
    
        println!("Parsed number: {}", num);
    }
    



  11. let else with structs
  12. struct Point { x: i32, y: i32 }
    
    let Point { x, y } = p else {
        panic!("Not a point!");
    };
    
    println!("({}, {})", x, y);
    



  13. Pattern guards are allowed
  14. let Some(v) = input else {
        panic!("Not an Option");
    };
    
    let n = v;
    
    let Some(x) = n.filter(|x| *x > 10) else {
        println!("Too small!");
        return;
    };
    



  15. The else block must break or return
  16. // ERROR: compiler does not allow falling through
    let Some(x) = maybe else {
        println!("No value");
        // nothing here — ERROR
    };
    



  17. Combining let else with references
  18. let Some(&num) = maybe_ref else {
        return;
    };
    
    println!("Number: {}", num);
    



  19. Chaining multiple let elses
  20. let Some(a) = opt_a else { return; };
    let Some(b) = opt_b else { return; };
    let Ok(sum) = add(a, b) else { return; };
    
    println!("Sum = {}", sum);
    





while let

  1. Introduction



  2. Basic while let Example
  3. let mut stack = vec![1, 2, 3];
    
    while let Some(top) = stack.pop() {
        println!("Popped: {}", top);
    }
    



  4. Equivalent to loop + if let
  5. let mut stack = vec![1, 2, 3];
    
    loop {
        if let Some(top) = stack.pop() {
            println!("Popped: {}", top);
        } else {
            break;
        }
    }
    



  6. Matching tuples with while let
  7. let mut iter = (0..5).enumerate();
    
    while let Some((index, value)) = iter.next() {
        println!("#{} = {}", index, value);
    }
    



  8. while let with Result<T, E>
  9. let mut input = vec!["10", "x", "20"].into_iter();
    
    while let Some(s) = input.next() {
        let Ok(n) = s.parse::<i32>() else {
            println!("Skipping invalid number: {}", s);
            continue;
        };
    
        println!("Parsed: {}", n);
    }
    



  10. while let with state machines
  11. enum State {
        Start,
        Number(i32),
        End,
    }
    
    let mut state = Some(State::Start);
    
    while let Some(s) = state {
        match s {
            State::Start => {
                println!("Starting...");
                state = Some(State::Number(42));
            }
            State::Number(n) => {
                println!("Number: {}", n);
                state = Some(State::End);
            }
            State::End => {
                println!("Finished.");
                state = None;
            }
        }
    }
    



  12. Processing I/O lines
  13. use std::io::{self, BufRead};
    
    let stdin = io::stdin();
    let mut lines = stdin.lock().lines();
    
    while let Some(Ok(line)) = lines.next() {
        println!("Input: {}", line);
    }
    



  14. while let with references
  15. let numbers = vec![10, 20, 30];
    let mut iter = numbers.iter();
    
    while let Some(&n) = iter.next() {
        println!("n = {}", n);
    }
    



  16. while let vs for loop

  17. Use while let when... Use for when...
    You must destructure Option or Result. You have a simple iterator.
    You want to stop upon None. You want to iterate exactly once over each element.
    You have stateful logic controlling next(). Your iterations are independent and clean.
    You need flexible custom loop breaking. Standard iteration is sufficient.


  18. Summary of while let





Methods

  1. Introduction



  2. Defining a Method
  3. struct Point {
        x: f64,
        y: f64,
    }
    
    impl Point {
        fn distance_from_origin(&self) -> f64 {
            (self.x.powi(2) + self.y.powi(2)).sqrt()
        }
    }
    

    let p = Point { x: 3.0, y: 4.0 };
    println!("{}", p.distance_from_origin());
    


  4. The Receiver: self, &self, &mut self


  5. Receiver Description Meaning
    self takes ownership method consumes the instance
    &self immutable borrow method reads but cannot modify
    &mut self mutable borrow method can modify the instance


  6. Methods with &mut self
  7. impl Point {
        fn move_by(&mut self, dx: f64, dy: f64) {
            self.x += dx;
            self.y += dy;
        }
    }
    
    let mut p = Point { x: 1.0, y: 2.0 };
    p.move_by(5.0, -1.0);
    



  8. Methods with self (consuming)
  9. impl Point {
        fn into_tuple(self) -> (f64, f64) {
            (self.x, self.y)
        }
    }
    
    let p = Point { x: 3.0, y: 4.0 };
    let t = p.into_tuple(); // p is moved and cannot be used again
    



  10. Multiple impl Blocks
  11. impl Point {
        fn x(&self) -> f64 { self.x }
    }
    
    impl Point {
        fn y(&self) -> f64 { self.y }
    }
    



  12. Associated Functions vs Methods
  13. impl Point {
        fn new(x: f64, y: f64) -> Self {
            Self { x, y }
        }
    }
    

    let p = Point::new(1.0, 2.0);
    


  14. Chaining Methods
  15. struct Counter { n: i32 }
    
    impl Counter {
        fn new() -> Self {
            Self { n: 0 }
        }
    
        fn inc(&mut self) -> &mut Self {
            self.n += 1;
            self
        }
    }
    
    let mut c = Counter::new();
    c.inc().inc().inc();
    



  16. Methods on Enums
  17. enum Shape {
        Circle(f64),
        Rect { w: f64, h: f64 },
    }
    
    impl Shape {
        fn area(&self) -> f64 {
            match self {
                Shape::Circle(r) => std::f64::consts::PI * r * r,
                Shape::Rect { w, h } => w * h,
            }
        }
    }
    



  18. Method Syntax Sugar: p.method() == Type::method(&p)
  19. p.distance_from_origin();
    
    // Is equivalent to:
    Point::distance_from_origin(&p);
    



  20. Methods with Generic Parameters
  21. struct Wrapper<T> {
        value: T,
    }
    
    impl<T> Wrapper<T> {
        fn get(&self) -> &T {
            &self.value
        }
    }
    



  22. Methods with where Clauses
  23. impl<T> Wrapper<T>
    where
        T: std::fmt::Display,
    {
        fn show(&self) {
            println!("{}", self.value);
        }
    }
    




Closures

  1. Introduction



  2. Basic Closure Syntax
  3. let add = |a, b| a + b;
    
    println!("{}", add(2, 3)); // 5
    



  4. Closures Capturing Environment
  5. let x = 10;
    
    let show = || println!("x = {}", x);
    
    show();
    



  6. Capture by Mutable Reference
  7. let mut counter = 0;
    
    let mut increment = || {
        counter += 1;
    };
    
    increment();
    increment();
    
    println!("{}", counter); // 2
    



  8. Capture by Move (Moving Ownership)
  9. let s = String::from("hello");
    
    let closure = move || {
        println!("inside: {}", s);
    };
    
    closure();
    
    // println!("{}", s); // ERROR: moved into closure
    



  10. Type Annotations for Closures
  11. let multiply = |a: i32, b: i32| -> i32 {
        a * b
    };
    



  12. Closures as Function Parameters
  13. fn apply<F>(f: F)
    where
        F: Fn(),
    {
        f();
    }
    
    apply(|| println!("Hello"));
    



  14. The Three Closure Traits

  15. Trait Capture Style Description
    Fn &T (immutable borrow) Used for closures that don't modify captured values
    FnMut &mut T (mutable borrow) Used for closures that modify captured variables
    FnOnce T (move) Used for closures that consume captured variables



  16. Returning Closures

  17. fn make_adder(x: i32) -> impl Fn(i32) -> i32 {
        move |y| x + y
    }
    
    let add10 = make_adder(10);
    println!("{}", add10(5)); // 15
    


  18. Closures in Iterator Adapters
  19. let nums = vec![1, 2, 3];
    
    let doubled: Vec<i32> = nums.iter()
        .map(|x| x * 2)
        .collect();
    
    println!("{:?}", doubled); // [2, 4, 6]
    



  20. Closures in Threads
  21. use std::thread;
    
    let s = String::from("hello");
    
    thread::spawn(move || {
        println!("{}", s);
    });
    



  22. Closures vs Functions

  23. Closures Functions
    Can capture environment Cannot capture any outside variable
    Anonymous, inline Named, standalone
    Type inferred automatically Types must be explicit
    Implement Fn / FnMut / FnOnce Functions are fn pointers



Higher-Order Functions

  1. Introduction



  2. Accepting a Closure as an Argument
  3. fn apply<F>(f: F)
    where
        F: Fn(),
    {
        f();
    }
    
    apply(|| println!("Hello from closure"));
    



  4. Passing Closures with Parameters
  5. fn compute<F>(op: F, a: i32, b: i32) -> i32
    where
        F: Fn(i32, i32) -> i32,
    {
        op(a, b)
    }
    
    let sum = compute(|x, y| x + y, 2, 3);
    println!("{}", sum); // 5
    



  6. Returning a Closure

  7. fn make_multiplier(x: i32) -> impl Fn(i32) -> i32 {
        move |y| x * y
    }
    
    let times3 = make_multiplier(3);
    
    println!("{}", times3(10)); // 30
    



  8. Returning Different Closures Based on Conditions
  9. fn choose(op: &str) -> impl Fn(i32, i32) -> i32 {
        match op {
            "add" => |a, b| a + b,
            "mul" => |a, b| a * b,
            _ => |_, _| 0,
        }
    }
    
    let adder = choose("add");
    println!("{}", adder(2, 3)); // 5
    



  10. Using Higher-Order Functions with Iterators
  11. let nums = vec![1, 2, 3, 4];
    
    let even_squares: Vec<i32> = nums
        .into_iter()
        .filter(|x| x % 2 == 0)
        .map(|x| x * x)
        .collect();
    
    println!("{:?}", even_squares); // [4, 16]
    



  12. fold: The Most General HOF
  13. let sum = (1..=5).fold(0, |acc, x| acc + x);
    
    println!("{}", sum); // 15
    



  14. Closures vs Function Pointers

  15. fn add(a: i32, b: i32) -> i32 { a + b }
    
    fn operate<F>(f: F) -> i32
    where
        F: Fn(i32, i32) -> i32,
    {
        f(3, 4)
    }
    
    println!("{}", operate(add));        // works
    println!("{}", operate(|x, y| x*y)); // works
    



  16. Higher-Order Functions with Generics
  17. fn transform_all<T, F>(items: Vec<T>, f: F) -> Vec<T>
    where
        F: Fn(T) -> T,
    {
        items.into_iter().map(f).collect()
    }
    
    let nums = vec![1, 2, 3];
    let doubled = transform_all(nums, |x| x * 2);
    
    println!("{:?}", doubled); // [2, 4, 6]
    



  18. Using HOFs as Callbacks
  19. fn notify<F>(msg: &str, f: F)
    where
        F: Fn(&str),
    {
        f(msg);
    }
    
    notify("Warning!", |text| println!("[LOG]: {}", text));
    



  20. Summary of Higher-Order Functions

  21. Concept Description
    Accept functions HOFs can take closures or function pointers as arguments
    Return functions HOFs may return closures using impl Fn
    Used in iterators map, filter, fold are all HOFs
    Enable declarative style Clean, chainable, functional pipelines
    Flexible capture rules Closures can capture variables via &, &mut, or move





Diverging Functions

  1. Introduction



  2. Syntax of a Diverging Function
  3. fn never_returns() -> ! {
        panic!("This function never returns");
    }
    



  4. Infinite Loops as Diverging Functions
  5. fn forever() -> ! {
        loop {
            println!("Running forever...");
        }
    }
    



  6. Diverging Functions in Error Handling
  7. fn expect_value(v: Option<i32>) -> i32 {
        match v {
            Some(n) => n,
            None => panic!("Expected a value"),
        }
    }
    



  8. The Never Type as a "Bottom Type"

  9. let x: i32 = {
        panic!("crash"); // type is `!` but coerced to i32
    };
    



  10. Using Diverging Functions for Exhaustive Matching
  11. enum Never {}
    
    fn impossible(n: Never) -> ! {
        match n {} // no variants, so this match is exhaustive
    }
    



  12. Useful for Marking Unreachable Code
  13. fn handle(value: Result<i32, &str>) -> i32 {
        match value {
            Ok(v) => v,
            Err(_) => unreachable!("Error should never occur"),
        }
    }
    



  14. Never Type in Control Flow
  15. fn compute(flag: bool) -> i32 {
        if flag {
            return 10;
        } else {
            panic!("bad flag"); // type = !
        }
    }
    



  16. Never Type in Matches
  17. let mut iter = vec![1].into_iter();
    
    match iter.next() {
        Some(v) => println!("{}", v),
        None => { continue; } // continue is diverging
    }
    



  18. Common Diverging Constructs

  19. Expression Type Description
    panic!() ! Terminates the program
    loop { ... } ! Infinite loop
    continue ! Exits current loop iteration
    break (no value) ! Exits the loop immediately
    return ! Leaves the function
    unimplemented!(), todo!() ! Marks incomplete code


  20. Summary of Diverging Functions





Modules in Rust

  1. Introduction



  2. Declaring a Module (Inline)
  3. mod api {
        pub fn hello() {
            println!("Hello from API!");
        }
    }
    
    fn main() {
        api::hello();
    }
    



  4. Declaring a Module in a Separate File

  5. src/
    ├── main.rs
    └── api.rs
    
    // main.rs
    mod api;           // declares the module (loads src/api.rs)
    fn main() {
        api::hello();
    }
    
    // api.rs
    pub fn hello() {
        println!("Hello from file module!");
    }
    



  6. Modules with Submodules

  7. src/
    ├── main.rs
    └── network/
        ├── mod.rs
        └── client.rs
    
    // main.rs
    mod network;
    
    fn main() {
        network::client::connect();
    }
    
    // network/mod.rs
    pub mod client;
    
    // network/client.rs
    pub fn connect() {
        println!("Client connected!");
    }
    



  8. The Modern Alternative: network.rs + network/ Directory

  9. src/
    ├── main.rs
    └── network.rs
    └── network/
        └── client.rs
    
    // network.rs
    pub mod client;
    



  10. Module Visibility

  11. mod a {
        pub mod b {
            pub(super) fn f() {}
        }
    }
    


  12. Using Other Modules

  13. mod math {
        pub fn add(a: i32, b: i32) -> i32 { a + b }
    }
    
    use math::add;
    
    fn main() {
        println!("{}", add(2, 3));
    }
    


  14. Absolute Paths vs Relative Paths

  15. crate::a::b::f();  // absolute path
    super::f();        // parent module
    self::g();         // current module
    



  16. Re-exporting Modules
  17. mod backend {
        pub fn init() {}
    }
    
    pub use backend::init; // re-export
    
    fn main() {
        init(); // available in root namespace
    }
    



  18. Common File Layout Patterns in Rust Projects

  19. Module Structure Description
    lib.rs Entry point for library crates
    main.rs Entry point for binary crates
    mod.rs (legacy) Module root inside directories
    module.rs + module/ Modern module + its submodules
    pub use Re-exporting to create clean public APIs




Visibility in Modules

  1. Introduction



  2. Default: Everything is Private
  3. mod a {
        fn secret() {
            println!("hidden");
        }
    }
    
    fn main() {
        // a::secret(); // ERROR: function is private
    }
    



  4. Making Items Public with pub
  5. mod a {
        pub fn hello() {
            println!("Hello!");
        }
    }
    
    fn main() {
        a::hello(); // OK
    }
    



  6. Public Structs with Private Fields
  7. mod user {
        pub struct User {
            pub name: String,
            age: u32, // private
        }
    
        impl User {
            pub fn new(name: String, age: u32) -> Self {
                Self { name, age }
            }
        }
    }
    
    fn main() {
        let u = user::User::new("Alice".into(), 20);
    
        println!("{}", u.name);
        // println!("{}", u.age); // ERROR: age is private
    }
    



  8. Visibility of Enums
  9. mod m {
        pub enum Color {
            Red,
            Green,
            Blue,
        }
    }
    
    fn main() {
        let c = m::Color::Red; // OK
    }
    



  10. pub(crate): Visible Within the Entire Crate
  11. mod internal {
        pub(crate) fn helper() {
            println!("crate-level visibility");
        }
    }
    



  12. pub(super): Visible Only to Parent Module
  13. mod a {
        mod b {
            pub(super) fn f() {
                println!("visible to parent (mod a)");
            }
        }
    
        pub fn call() {
            b::f(); // OK
        }
    }
    
    fn main() {}
    



  14. pub(in path): Visible Only Within a Specific Module
  15. mod a {
        pub mod b {
            pub(in crate::a) fn f() {
                println!("visible only inside mod a");
            }
        }
    
        fn call() {
            b::f(); // OK
        }
    }
    
    fn main() {
        // a::b::f(); // ERROR
    }
    



  16. pub(self): Visible Only Inside the Current Module
  17. mod a {
        pub(self) fn f() {
            println!("only inside a");
        }
    }
    



  18. pub(restricted) Summary

  19. Keyword Visibility
    pub Visible everywhere
    pub(crate) Visible in the current crate
    pub(super) Visible to parent module
    pub(in path) Visible in a specific module
    pub(self) Visible only in the current module (default)


  20. Re-exporting with pub use
  21. mod backend {
        pub fn init() {
            println!("backend init");
        }
    }
    
    pub use backend::init; // re-export
    
    fn main() {
        init(); // OK
    }
    





The use Keyword in Rust

  1. Introduction



  2. Basic Usage
  3. use std::collections::HashMap;
    
    fn main() {
        let mut map = HashMap::new();
    }
    

    let mut map = std::collections::HashMap::new();
    


  4. Using Standard Library Items
  5. use std::fs::File;
    use std::io::{self, Read};
    
    fn main() -> io::Result<()> {
        let mut file = File::open("data.txt")?;
        let mut buffer = String::new();
        file.read_to_string(&mut buffer)?;
        Ok(())
    }
    



  6. Using 3rd-Party Crates

  7. [dependencies]
    rand = "0.8"
    serde = "1.0"
    
    use rand::Rng;
    
    fn main() {
        let n = rand::thread_rng().gen_range(1..=10);
        println!("Random: {}", n);
    }
    



  8. Using Your Own Modules
  9. // src/math.rs
    pub fn add(a: i32, b: i32) -> i32 { a + b }
    
    // src/main.rs
    mod math;
    use math::add;
    
    fn main() {
        println!("{}", add(5, 3));
    }
    



  10. Using Nested Submodules
  11. src/
    ├── main.rs
    └── network/
        ├── mod.rs
        └── client.rs
    
    // network/mod.rs
    pub mod client;
    
    // network/client.rs
    pub fn connect() {
        println!("Connected!");
    }
    
    // main.rs
    mod network;
    use network::client::connect;
    
    fn main() {
        connect();
    }
    


  12. Using Multiple Imports from the Same Module
  13. use std::cmp::{min, max};
    



  14. Using Everything in a Module (Glob Import)
  15. use std::collections::*;
    



  16. Renaming Imports with as
  17. use std::io::Result as IoResult;
    
    fn example() -> IoResult<()> {
        Ok(())
    }
    



  18. Importing Traits (Required for Methods!)
  19. use std::io::Read;
    
    let mut buffer = String::new();
    file.read_to_string(&mut buffer); // method from Read trait
    



  20. Importing Enums and Variants
  21. use std::cmp::Ordering;
    
    match x.cmp(&y) {
        Ordering::Less => {}
        Ordering::Equal => {}
        Ordering::Greater => {}
    }
    
    use std::cmp::Ordering::{Less, Equal, Greater};
    
    match x.cmp(&y) {
        Less => {}
        Equal => {}
        Greater => {}
    }
    



  22. Re-exporting (`pub use`)
  23. mod utils {
        pub fn greet() { println!("hi"); }
    }
    
    pub use utils::greet;  // re-export
    
    fn main() {
        greet(); // available at crate root
    }
    



  24. Self and Super Imports
  25. use self::math::add;
    use super::config::load_config;
    



  26. Summary





Crates in Rust

  1. Introduction



  2. Binary Crates

  3. src/
    └── main.rs
    
    // main.rs
    fn main() {
        println!("Hello from a binary crate!");
    }
    



  4. Library Crates

  5. src/
    └── lib.rs
    
    // lib.rs
    pub fn greet(name: &str) {
        println!("Hello, {}!", name);
    }
    



  6. Project Structure: One Package, Multiple Crates

  7. src/
    ├── lib.rs       # library crate
    ├── main.rs      # default binary crate
    └── bin/
        ├── tool1.rs # binary crate 1
        └── tool2.rs # binary crate 2
    



  8. The Crate Root

  9. src/main.rs  # crate root for binary crate
    src/lib.rs   # crate root for library crate
    



  10. Cargo.toml Defines the Crate
  11. [package]
    name = "my_project"
    version = "0.1.0"
    edition = "2021"
    
    [dependencies]
    serde = "1.0"
    rand = "0.8"
    



  12. External Crates
  13. use rand::Rng;
    
    fn main() {
        let n: u32 = rand::thread_rng().gen_range(1..=10);
        println!("{}", n);
    }
    



  14. Preludes and the Name `crate`

  15. crate::utils::math::add(2, 3);
    



  16. Crates.io and Publishing

  17. $ cargo publish
    



  18. Building and Running Crates
  19. $ cargo build         # build the crate
    $ cargo build --release
    $ cargo run           # binary crates only
    $ cargo test          # test library + binaries
    $ cargo doc --open    # generate and open crate docs
    



  20. Crates vs Modules

  21. Concept Level Description
    Crate Compilation Unit Produces a binary or library
    Module Namespace Unit Organizes code inside a crate
    Package Project Unit Contains Cargo.toml and zero/many crates




Attributes in Rust

  1. Introduction



  2. Outer Attributes
  3. #[derive(Debug)]
    struct User {
        id: u32,
        name: String,
    }
    



  4. Inner Attributes
  5. #![allow(unused)]
    mod utils {
        fn temp() {}
    }
    



  6. Derive Attributes

  7. #[derive(Debug, Clone, Copy, PartialEq)]
    struct Point {
        x: i32,
        y: i32,
    }
    



  8. Conditional Compilation Attributes
  9. #[cfg(target_os = "linux")]
    fn platform_only() {
        println!("Running on Linux");
    }
    
    #[cfg(feature = "fast_mode")]
    fn fast() {}
    

    fn main() {
        #[cfg(debug_assertions)]
        println!("Running in debug mode");
    }
    


  10. Allow, Warn, and Deny Lints
  11. #[allow(dead_code)]
    fn unused() {}
    
    #[warn(missing_docs)]
    fn documented() {}
    
    #[deny(warnings)]
    fn strict() {}
    



  12. Documentation Attributes (rustdoc)
  13. #![doc = "A crate-level description"]
    
    /// Adds two numbers.
    ///
    /// # Example
    /// ```
    /// assert_eq!(3, add(1, 2));
    /// ```
    #[doc(alias = "plus")]
    pub fn add(a: i32, b: i32) -> i32 {
        a + b
    }
    



  14. Test Attributes
  15. #[cfg(test)]
    mod tests {
        #[test]
        fn it_works() {
            assert_eq!(2 + 2, 4);
        }
    
        #[test]
        #[should_panic]
        fn should_fail() {
            panic!("panics as expected");
        }
    }
    



  16. Inline and Macro Attributes
  17. #[inline]
    fn fast_add(a: i32, b: i32) -> i32 {
        a + b
    }
    
    #[inline(always)]
    fn really_inline(a: i32, b: i32) -> i32 {
        a + b
    }
    
    #[macro_export]
    macro_rules! hello {
        () => {
            println!("Hello from macro!");
        };
    }
    



  18. Serde Attributes (3rd-Party Example)
  19. use serde::{Serialize, Deserialize};
    
    #[derive(Serialize, Deserialize)]
    struct User {
        #[serde(rename = "user_id")]
        id: u32,
    
        #[serde(skip_serializing)]
        password: String,
    }
    



  20. Entry Point Attribute
  21. #[no_mangle]
    pub extern "C" fn my_entry() {}
    



  22. Crate-Level Attributes
  23. #![allow(unused)]
    #![warn(missing_docs)]
    #![cfg_attr(debug_assertions, feature(explicit_generic_args_with_impl_trait))]
    



  24. Attribute Summary Table

  25. Attribute Purpose Example
    #[derive] Auto-impl common traits #[derive(Debug, Clone)]
    #[cfg] Conditional compilation #[cfg(unix)]
    #[allow], #[warn], #[deny] Lint control #[allow(dead_code)]
    #[test] Unit test functions #[test]
    #[inline] Suggest inline expansion #[inline(always)]
    #[doc] Documentation metadata #[doc(alias = "x")]
    #[macro_export] Expose macros publicly #[macro_export]
    #![crate_attr] Crate-level behavior #![allow(unused)]


  26. Summary





Defining Custom Attributes in Rust (Beginner Level)

  1. Introduction



  2. Three Kinds of Procedural Macros that Create Attributes




  3. Project Setup for Custom Attributes

  4. $ cargo new my_macros --lib
    $ cd my_macros
    
    # Edit Cargo.toml to enable procedural macros
    
    [lib]
    proc-macro = true
    



  5. Example 1: Creating a Simple Derive Macro (easiest form)
  6. // my_macros/src/lib.rs
    
    use proc_macro::TokenStream;
    
    #[proc_macro_derive(HelloMacro)]
    pub fn hello_macro(_input: TokenStream) -> TokenStream {
        // At beginner level, return nothing or simple message
        // A real macro would inspect and modify the input code.
        TokenStream::new()
    }
    

    // in another crate:
    
    use my_macros::HelloMacro;
    
    #[derive(HelloMacro)]
    struct User;
    



  7. Example 2: A Very Simple Attribute Macro
  8. // inside my_macros/src/lib.rs
    
    use proc_macro::TokenStream;
    
    #[proc_macro_attribute]
    pub fn debug_message(_attr: TokenStream, item: TokenStream) -> TokenStream {
        println!("debug_message attribute was used!");
        item  // return the original item unchanged
    }
    

    // in a binary or library crate
    
    use my_macros::debug_message;
    
    #[debug_message]
    fn greet() {
        println!("Hello!");
    }
    



  9. Example 3: Attribute Macro That Modifies Code (Still Beginner Level)
  10. // my_macros/src/lib.rs
    
    use proc_macro::TokenStream;
    use quote::quote;
    use syn;
    
    #[proc_macro_attribute]
    pub fn make_public(_attr: TokenStream, item: TokenStream) -> TokenStream {
        let mut ast = syn::parse_macro_input!(item as syn::ItemFn);
        ast.vis = syn::Visibility::Public;
    
        let expanded = quote! { #ast };
        expanded.into()
    }
    

    use my_macros::make_public;
    
    #[make_public]
    fn secret() {
        println!("This is now public!");
    }
    



  11. How Custom Attributes Work Internally (Beginner Explanation)



  12. Limitations of Custom Attributes



  13. Summary





The dead_code Attribute in Rust

  1. Introduction



  2. Why Does Rust Warn About Dead Code?



  3. Basic Usage of #[allow(dead_code)]
  4. #[allow(dead_code)]
    fn unused_function() {
        println!("This function is never called");
    }
    



  5. Allowing Dead Code for Structs and Enums
  6. #[allow(dead_code)]
    struct Config {
        debug: bool,
        retries: u32,
    }
    
    #[allow(dead_code)]
    enum Status {
        Ok,
        Error,
    }
    



  7. Silencing Dead Code for an Entire Module
  8. #[allow(dead_code)]
    mod utils {
        fn unused_a() {}
        fn unused_b() {}
    }
    



  9. Crate-Level Dead Code Attribute
  10. #![allow(dead_code)]
    
    fn a() {}
    fn b() {}
    
    mod helpers {
        fn c() {}
    }
    



  11. When Should You Use dead_code?



  12. Combining with cfg Attributes

  13. #[cfg(unix)]
    fn unix_only() {}
    
    #[cfg(windows)]
    #[allow(dead_code)]
    fn unix_only() {}  // unused on Windows
    


  14. Dead Code on Private Items Only

  15. pub fn api_entry() {} // never warns
    




The cfg Attribute in Rust

  1. Introduction: What is cfg?



  2. Two Forms: Attribute #[cfg] and Conditional Block cfg!

  3. #[cfg(unix)]
    fn platform() { println!("running on unix"); }
    
    #[cfg(windows)]
    fn platform() { println!("running on windows"); }
    
    fn main() {
        platform();
    }
    


  4. OS-Based Conditions
  5. #[cfg(target_os = "linux")]
    fn only_linux() {
        println!("This runs on Linux");
    }
    
    #[cfg(target_os = "windows")]
    fn only_windows() {
        println!("This runs on Windows");
    }
    



  6. Architecture Conditions
  7. #[cfg(target_arch = "x86_64")]
    fn arch_fn() { println!("x86_64 CPU"); }
    
    #[cfg(target_arch = "aarch64")]
    fn arch_fn() { println!("ARM64 CPU"); }
    



  8. Debug vs Release Mode
  9. #[cfg(debug_assertions)]
    fn debug_mode() {
        println!("Compiled in debug mode");
    }
    
    #[cfg(not(debug_assertions))]
    fn debug_mode() {
        println!("Compiled in release mode");
    }
    



  10. Using Cargo Features

  11. [features]
    fast = []
    gui = []
    
    #[cfg(feature = "fast")]
    fn run() {
        println!("Fast mode enabled");
    }
    
    #[cfg(not(feature = "fast"))]
    fn run() {
        println!("Normal mode");
    }
    

    $ cargo run --features fast
    


  12. Combining Conditions

  13. #[cfg(all(unix, target_arch = "x86_64"))]
    fn example() { println!("Unix + x86_64"); }
    
    #[cfg(any(windows, target_os = "macos"))]
    fn example() { println!("Windows OR macOS"); }
    
    #[cfg(not(debug_assertions))]
    fn example() { println!("Not debug"); }
    


  14. Conditional Modules
  15. #[cfg(feature = "gui")]
    mod gui;
    
    #[cfg(feature = "cli")]
    mod cli;
    



  16. Conditional Blocks Using cfg!

  17. fn main() {
        if cfg!(windows) {
            println!("This binary was compiled for Windows");
        }
    
        if cfg!(target_arch = "aarch64") {
            println!("Compiled for ARM64");
        }
    }
    


  18. Conditional Use Statements
  19. #[cfg(windows)]
    use winapi::um::winuser::MessageBoxA;
    
    #[cfg(unix)]
    use libc::printf;
    



  20. Conditional Struct Fields
  21. struct Config {
        #[cfg(feature = "gui")]
        window_size: u32,
    
        #[cfg(feature = "cli")]
        terminal_colors: u8,
    }
    



  22. Conditional Functions Inside Modules
  23. mod util {
        #[cfg(feature = "fast")]
        pub fn compute() { println!("fast compute"); }
    
        #[cfg(not(feature = "fast"))]
        pub fn compute() { println!("normal compute"); }
    }
    


  24. Common cfg Targets Summary

  25. Condition Example Description
    target_os #[cfg(target_os = "linux")] OS-specific code
    target_arch #[cfg(target_arch = "x86_64")] CPU architecture
    debug_assertions #[cfg(debug_assertions)] Debug mode
    feature #[cfg(feature = "fast")] Cargo feature flags
    unix, windows #[cfg(unix)] Platform families
    test #[cfg(test)] Unit test code only
    not, all, any #[cfg(not(windows))] Condition combinators


  26. Summary





Generics in Functions in Rust

  1. Rust enforces that generics remain zero-cost abstractions:


  2. Basic Syntax of Generic Functions

  3. fn identity<T>(value: T) -> T {
        value
    }
    
    fn main() {
        let x = identity(10);
        let y = identity("hello");
        println!("{}", x);
        println!("{}", y);
    }
    


  4. Multiple Generic Parameters
  5. fn pair<A, B>(a: A, b: B) -> (A, B) {
        (a, b)
    }
    
    fn main() {
        let p = pair(10, "abc");
        println!("{:?}", p);
    }
    


  6. Generics With Constraints (Traits)

  7. fn print_value<T: std::fmt::Display>(value: T) {
        println!("{}", value);
    }
    
    fn main() {
        print_value(123);
        print_value("hello");
    }
    


  8. Where Clauses

  9. fn compare<T>(a: T, b: T) -> bool
    where
        T: PartialEq,
    {
        a == b
    }
    


  10. Generic Functions With Multiple Trait Bounds
  11. fn summary<T: std::fmt::Debug + Clone>(value: T) {
        println!("{:?}", value.clone());
    }
    
    fn main() {
        summary(vec![1, 2, 3]);
    }
    


  12. Generic Functions and Monomorphization

  13. fn square<T: std::ops::Mul<Output = T> + Copy>(x: T) -> T {
        x * x
    }
    
    fn main() {
        println!("{}", square(3));     // generates int version
        println!("{}", square(3.14));  // generates float version
    }
    


  14. Using Generics for Utility Functions
  15. fn swap<T>(a: &mut T, b: &mut T) {
        let temp = std::mem::replace(a, std::mem::take(b));
        std::mem::replace(b, temp);
    }
    
    fn main() {
        let mut x = 1;
        let mut y = 2;
        swap(&mut x, &mut y);
        println!("{} {}", x, y);
    }
    


  16. Generics vs Dynamic Dispatch (Comparison)

  17. fn print_any<T: std::fmt::Debug>(value: T) {
        println!("{:?}", value);     // generics
    }
    
    fn print_any_dyn(value: &dyn std::fmt::Debug) {
        println!("{:?}", value);     // trait object
    }
    


  18. Common Patterns with Generic Functions

  19. Pattern Example Description
    Simple generic fn foo<T>(...) Type-independent algorithm
    Trait bound T: Display Restrict types
    Multiple bounds T: Debug + Clone Advanced constraints
    Where clause where T: Ord Readable bound style
    Multiple generics <A, B> Multi-type functions
    Monomorphization fn foo<T>(x: T) Zero-cost abstractions


  20. Summary





Generics Implemented in Rust

  1. Rust allows generics in:


  2. Generic impl for a Generic Struct

  3. struct Point<T> {
        x: T,
        y: T,
    }
    
    impl<T> Point<T> {
        fn new(x: T, y: T) -> Self {
            Self { x, y }
        }
    
        fn x(&self) -> &T {
            &self.x
        }
    }
    


  4. Separate impl Blocks for Different Type Constraints

  5. impl<T: std::fmt::Display> Point<T> {
        fn show(&self) {
            println!("({}, {})", self.x, self.y);
        }
    }
    


  6. Using where Clauses in Generic Implementations

  7. impl<T> Point<T>
    where
        T: Clone + PartialEq,
    {
        fn is_square(&self) -> bool {
            self.x.clone() == self.y.clone()
        }
    }
    


  8. Generics in Methods Without Making Struct Generic

  9. struct Logger;
    
    impl Logger {
        fn print_any<T: std::fmt::Debug>(&self, value: T) {
            println!("{:?}", value);
        }
    }
    


  10. Implementing Traits with Generics

  11. trait ToTuple<A, B> {
        fn to_tuple(&self) -> (A, B);
    }
    
    impl<T: Clone> ToTuple<T, T> for Point<T> {
        fn to_tuple(&self) -> (T, T) {
            (self.x.clone(), self.y.clone())
        }
    }
    


  12. Implementing Traits for Concrete Types but Using Generics
  13. trait ShowMe {
        fn show_any<T: std::fmt::Debug>(value: T);
    }
    
    struct DisplayTool;
    
    impl ShowMe for DisplayTool {
        fn show_any<T: std::fmt::Debug>(value: T) {
            println!("{:?}", value);
        }
    }
    


  14. Specialization Using Different impl Blocks

  15. impl Point<i32> {
        fn distance_from_origin(&self) -> f64 {
            ((self.x.pow(2) + self.y.pow(2)) as f64).sqrt()
        }
    }
    


  16. Generic Implementations for Enums
  17. enum Container<T> {
        One(T),
        Two(T, T),
    }
    
    impl<T> Container<T> {
        fn count(&self) -> usize {
            match self {
                Container::One(_) => 1,
                Container::Two(_, _) => 2,
            }
        }
    }
    


  18. Adding Trait Bounds to Generic impl for Enums
  19. impl<T: std::fmt::Debug> Container<T> {
        fn print(&self) {
            println!("{:?}", self);
        }
    }
    


  20. Multiple Generic Parameters in impl
  21. struct Pair<A, B> {
        left: A,
        right: B,
    }
    
    impl<A, B> Pair<A, B> {
        fn swap(self) -> Pair<B, A> {
            Pair {
                left: self.right,
                right: self.left,
            }
        }
    }
    


  22. Common Patterns in Generic impl Blocks

  23. Pattern Example Description
    Generic struct impl impl<T> Struct<T> Universal methods
    Trait-bound impl impl<T: Clone> Struct<T> Conditional methods
    Where clause where T: Ord + Debug Cleaner constraints
    Concrete specialization impl Struct<i32> Methods for specific types
    Enum generics impl<T> Enum<T> Reusable logic
    Trait impl with generics impl<T> Trait for Struct<T> Generic behavior




Traits in Rust

  1. What Are Traits?



  2. Defining a Trait
  3. trait Greet {
        fn greet(&self);
    }
    


  4. Implementing a Trait for a Type
  5. struct Person {
        name: String,
    }
    
    impl Greet for Person {
        fn greet(&self) {
            println!("Hello, {}!", self.name);
        }
    }
    


  6. Default Method Implementations
  7. trait Hello {
        fn say(&self) {
            println!("Hello from default method!");
        }
    }
    
    struct User;
    
    impl Hello for User {}  // inherits default
    


  8. Traits with Multiple Methods
  9. trait MathOps {
        fn double(&self) -> Self;
        fn triple(&self) -> Self;
    }
    
    impl MathOps for i32 {
        fn double(&self) -> Self { self * 2 }
        fn triple(&self) -> Self { self * 3 }
    }
    


  10. Traits with Associated Types

  11. trait Iterator {
        type Item;       // Each implementor chooses what 'Item' is.
    
        fn next(&mut self) -> Option<Self::Item>;
    }
    
    struct Counter {
        current: u32,
        max: u32,
    }
    
    impl Iterator for Counter {
        type Item = u32;   // We specify the concrete associated type here.
    
        fn next(&mut self) -> Option<Self::Item> {
            if self.current < self.max {
                let v = self.current;
                self.current += 1;
                Some(v)
            } else {
                None
            }
        }
    }
    


  12. Traits With Generic Methods
  13. trait Echo {
        fn echo<T: std::fmt::Debug>(&self, value: T) {
            println!("{:?}", value);
        }
    }
    
    struct Logger;
    
    impl Echo for Logger {}
    


  14. Trait Bounds: Using Traits With Generics

  15. fn print_any<T: std::fmt::Debug>(value: T) {
        println!("{:?}", value);
    }
    


  16. Multiple Trait Bounds
  17. fn compare_and_show<T: PartialEq + std::fmt::Debug>(a: T, b: T) {
        println!("equal? {}", a == b);
        println!("{:?}", a);
    }
    


  18. Where Clauses for Cleaner Trait Bounds
  19. fn sort_values<T>(values: &mut [T])
    where
        T: Ord + Clone,
    {
        values.sort();
    }
    


  20. Static Dispatch vs Dynamic Dispatch

  21. // static dispatch
    fn process_static<T: Greet>(x: T) {
        x.greet();
    }
    
    // dynamic dispatch
    fn process_dyn(x: &dyn Greet) {
        x.greet();
    }
    


  22. Derivable Traits

  23. #[derive(Debug, Clone, PartialEq, Eq)]
    struct User {
        id: i32,
    }
    


  24. Supertraits

  25. trait Printable: std::fmt::Display {
        fn print(&self) {
            println!("{}", self);
        }
    }
    


  26. Traits With Default Generic Parameters

  27. trait Storage<T = String> {
        fn store(&self, value: T);
    }
    
    struct Logger;
    
    // Uses the default: T = String
    impl Storage for Logger {
        fn store(&self, value: String) {
            println!("{}", value);
        }
    }
    
    struct IntLogger;
    
    // Override the default: T = i32
    impl Storage<i32> for IntLogger {
        fn store(&self, value: i32) {
            println!("number: {}", value);
        }
    }
    


  28. Common Standard Library Traits

  29. Trait Purpose Example
    Debug Debug formatting println!("{:?}", x)
    Display User-friendly formatting println!("{}", x)
    Clone Duplicate values x.clone()
    Copy Implicit copying All integers implement this
    PartialEq Equality a == b
    Ord Ordering values.sort()
    Iterator Iteration protocol for x in iter



Where Do Generics Go in Rust? (<T> Placement Guide)

  1. In Rust, angle brackets <...> appear in two main roles:

    1. Declaring generics: introducing type parameters: struct Foo<T> { ... }, impl<T> Foo<T> { ... }, fn foo<T>(...)

    2. Using generics: applying concrete types to a generic item: Vec<i32>, Option<String>, impl Storage<i32> for IntLogger


  2. Declaring Generics on Types and Functions

  3. struct Wrapper<T> {
        value: T,
    }
    
    enum Result<T, E> {
        Ok(T),
        Err(E),
    }
    
    trait Storage<T> {
        fn store(&self, value: T);
    }
    
    fn identity<T>(value: T) -> T {
        value
    }
    


  4. Declaring Generics on impl Blocks

  5. struct Point<T> {
        x: T,
        y: T,
    }
    
    // Declare T on the impl:
    impl<T> Point<T> {
        fn new(x: T, y: T) -> Self {
            Self { x, y }
        }
    
        fn x(&self) -> &T {
            &self.x
        }
    }
    


  6. Using Generics: Applying Concrete Types

  7. let p_int: Point<i32> = Point::new(1, 2);
    let p_str: Point<&str> = Point::new("x", "y");
    
    trait Storage<T> {
        fn store(&self, value: T);
    }
    
    struct IntStorage;
    
    // Implement Storage for the concrete type T = i32
    impl Storage<i32> for IntStorage {
        fn store(&self, value: i32) {
            println!("storing number: {}", value);
        }
    }
    


  8. Generic impl vs Concrete impl

  9. struct Boxed<T> {
        value: T,
    }
    
    // 1. Generic impl: applies to all T
    impl<T> Boxed<T> {
        fn value(&self) -> &T {
            &self.value
        }
    }
    
    // 2. Concrete impl: only for Boxed<i32>
    impl Boxed<i32> {
        fn is_positive(&self) -> bool {
            self.value > 0
        }
    }
    


  10. Traits + Generics: Where to Put <T>?

  11. trait ToPair<A, B> {
        fn to_pair(&self) -> (A, B);
    }
    
    struct PairHolder<T> {
        left: T,
        right: T,
    }
    
    // Declare T on impl, use T, A, B on the trait and type
    impl<T: Clone> ToPair<T, T> for PairHolder<T> {
        fn to_pair(&self) -> (T, T) {
            (self.left.clone(), self.right.clone())
        }
    }
    


  12. Generic Methods on Non-Generic Types

  13. struct Logger;
    
    // Logger itself is not generic
    impl Logger {
        // Method is generic
        fn log_any<T: std::fmt::Debug>(&self, value: T) {
            println!("{:?}", value);
        }
    }
    


  14. Traits With Default Generic Parameters

  15. trait Storage<T = String> {
        fn store(&self, value: T);
    }
    
    struct Logger;
    
    // Uses the default: T = String
    impl Storage for Logger {
        fn store(&self, value: String) {
            println!("{}", value);
        }
    }
    
    struct IntLogger;
    
    // Overrides the default: T = i32
    impl Storage<i32> for IntLogger {
        fn store(&self, value: i32) {
            println!("number: {}", value);
        }
    }
    


  16. Associated Types vs Generic Parameters

  17. trait Iterator {
        type Item;
    
        fn next(&mut self) -> Option<Self::Item>;
    }
    
    struct Counter {
        current: u32,
        max: u32,
    }
    
    impl Iterator for Counter {
        type Item = u32;
    
        fn next(&mut self) -> Option<Self::Item> {
            if self.current < self.max {
                let v = self.current;
                self.current += 1;
                Some(v)
            } else {
                None
            }
        }
    }
    


  18. Cheat Sheet: Where Do the Angle Brackets Go?

  19. Pattern Location of <...> Meaning
    struct Foo<T> After struct Declare a generic type parameter on the struct.
    fn foo<T>(...) After function name Declare method/function generics.
    trait Trait<T> After trait Declare generic parameters on a trait.
    impl<T> Foo<T> After impl Declare generics for the impl block.
    impl Foo<i32> After type name Use a concrete type for a non-generic impl.
    impl Trait for Foo No angle brackets Non-generic trait impl using defaults or no generics.
    impl Trait<i32> for Foo After trait name Implement a trait specialized to a concrete type.
    Vec<i32>, Option<String> After type name Apply a concrete type to a generic type.



Generics Bounds in Rust

  1. What Are Generic Bounds?



  2. Basic Trait Bound Syntax on Functions

  3. fn identity<T>(value: T) -> T {
        value
    }
    

    use std::fmt::Display;
    
    fn print_value<T: Display>(value: T) {
        println!("value = {}", value);
    }
    
    fn main() {
        print_value(42);                // i32 implements Display
        print_value("hello");           // &str implements Display
        // print_value(vec![1, 2, 3]);  // <-- does not compile: Vec<i32> does not implement Display
    }
    



  4. Multiple Trait Bounds on a Type Parameter

  5. use std::fmt::Display;
    
    fn print_and_clone<T: Display + Clone>(value: T) {
        println!("value = {}", value);
        let another = value.clone();
        println!("cloned = {}", another);
    }
    
    use std::fmt::Display;
    
    fn compare_and_print<T, U>(x: T, y: U)
    where
        T: Display + PartialOrd,
        U: Display + PartialOrd,
    {
        if x >= y {
            println!("x ("{}") is greater or equal to y ("{}")", x, y);
        } else {
            println!("x ("{}") is less than y ("{}")", x, y);
        }
    }
    


  6. Bounds on Structs and Enums

  7. use std::fmt::Display;
    
    struct Wrapper<T: Display> {
        inner: T,
    }
    
    impl<T: Display> Wrapper<T> {
        fn show(&self) {
            println!("Wrapper contains: {}", self.inner);
        }
    }
    
    struct Boxed<T> {
        inner: T,
    }
    
    // Only the methods require Display, not the type itself:
    impl<T: Display> Boxed<T> {
        fn print(&self) {
            println!("Boxed: {}", self.inner);
        }
    }
    


  8. Bounds on impl Blocks and Methods

  9. use std::fmt::Display;
    
    struct Pair<T> {
        x: T,
        y: T,
    }
    
    // Methods available for all T:
    impl<T> Pair<T> {
        fn new(x: T, y: T) -> Self {
            Self { x, y }
        }
    }
    
    // Extra methods only if T: Display + PartialOrd:
    impl<T> Pair<T>
    where
        T: Display + PartialOrd,
    {
        fn cmp_display(&self) {
            if self.x >= self.y {
                println!("The larger member is x = {}", self.x);
            } else {
                println!("The larger member is y = {}", self.y);
            }
        }
    }
    


  10. impl Trait as an Alternative to Explicit Type Parameters

  11. use std::fmt::Display;
    
    // Instead of: fn show<T: Display>(value: T)
    fn show(value: impl Display) {
        println!("value = {}", value);
    }
    
    use std::fmt::Display;
    
    fn make_message() -> impl Display {
        // Compiler picks a concrete type (here, String),
        // but callers only know "it implements Display".
        String::from("Hello from impl Trait!")
    }
    


  12. Trait Bounds vs. Lifetimes (Short Overview)

  13. use std::fmt::Display;
    
    fn print_ref<'a, T>(x: &'a T)
    where
        T: Display + 'a,
    {
        println!("x = {}", x);
    }
    


  14. Blanket Implementations and the Power of Bounds

  15. use std::fmt::Display;
    
    // Hypothetical example:
    trait PrettyPrint {
        fn pretty_print(&self);
    }
    
    impl<T: Display> PrettyPrint for T {
        fn pretty_print(&self) {
            println!("[[ {} ]]", self);
        }
    }
    
    fn main() {
        42.pretty_print();
        "hello".pretty_print();
    }
    




The Newtype Idiom in Rust

  1. What Is the Newtype Idiom?



  2. Basic Newtype Syntax

  3. struct UserId(u32);
    
    fn main() {
        let id = UserId(42);
    }
    
    fn show_user(id: UserId) {
        println!("UserId = {}", id.0);
    }
    
    fn main() {
        show_user(UserId(1));   // OK
        // show_user(1);        // ERROR: expected UserId, found u32
    }
    
    use std::fmt::Display;
    
    struct Meters(u32);
    
    impl Display for Meters {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            write!(f, "{} m", self.0)
        }
    }
    
    fn main() {
        let distance = Meters(120);
        println!("{}", distance);    // prints: 120 m
    }
    


  4. Newtype for API Restriction

  5. struct SafeIndex(usize);
    
    impl SafeIndex {
        fn new(i: usize) -> Option<Self> {
            if i < 10 {
                Some(Self(i))
            } else {
                None
            }
        }
    
        fn get(&self) -> usize {
            self.0
        }
    }
    


  6. Newtype for Deref-like Behavior

  7. use std::ops::Deref;
    
    struct MyBox<T>(T);
    
    impl<T> Deref for MyBox<T> {
        type Target = T;
    
        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }
    
    fn main() {
        let x = MyBox(10);
        println!("{}", *x); // acts like &T
    }
    


  8. Newtype Pattern for Nominal Typing

  9. struct Celsius(f64);
    struct Fahrenheit(f64);
    
    fn main() {
        let c = Celsius(30.0);
        let f = Fahrenheit(86.0);
        // They are not interchangeable even though both wrap f64.
    }
    


  10. Tuple Newtypes vs. Braced Newtypes

  11. struct Age(u8);
    
    struct Age {
        value: u8,
    }
    



  12. Zero-Cost Abstraction



  13. The `From` / `Into` Convenience

  14. struct Username(String);
    
    impl From<String> for Username {
        fn from(s: String) -> Self {
            Username(s)
        }
    }
    
    let name: Username = "hwangfucius".to_string().into();
    



Associated Items and Associated Types in Rust

  1. What Are Associated Items?



  2. Associated Functions (Inherent Methods)

  3. struct Point {
        x: i32,
        y: i32,
    }
    
    impl Point {
        // Associated function (like a constructor)
        fn new(x: i32, y: i32) -> Self {
            Self { x, y }
        }
    
        // Method (has &self)
        fn length_squared(&self) -> i32 {
            self.x * self.x + self.y * self.y
        }
    }
    
    fn main() {
        let p = Point::new(3, 4);           // call associated function
        println!("{}", p.length_squared()); // call method
    }
    


  4. Associated Constants

  5. struct Circle {
        radius: f64,
    }
    
    impl Circle {
        const PI: f64 = 3.141592653589793;
    
        fn area(&self) -> f64 {
            Self::PI * self.radius * self.radius
        }
    }
    
    fn main() {
        println!("{}", Circle::PI);   // access associated constant
        let c = Circle { radius: 2.0 };
        println!("{}", c.area());
    }
    


  6. Associated Types in Traits: The Basic Idea

  7. trait Iterator {
        type Item; // associated type
    
        fn next(&mut self) -> Option<Self::Item>;
    }
    

    struct Counter {
        current: u32,
    }
    
    impl Iterator for Counter {
        type Item = u32; // choose the concrete type
    
        fn next(&mut self) -> Option<Self::Item> {
            if self.current < 5 {
                self.current += 1;
                Some(self.current)
            } else {
                None
            }
        }
    }
    


  8. Associated Types vs. Generic Parameters on Traits

  9. trait IteratorGeneric<T> {
        fn next(&mut self) -> Option<T>;
    }
    
    // Associated type style:
    trait IntoIterator {
        type Item;
        type IntoIter: Iterator<Item = Self::Item>;
    
        fn into_iter(self) -> Self::IntoIter;
    }
    


  10. Using Associated Types in Trait Bounds

  11. fn sum_iter<I>(mut iter: I) -> i32
    where
        I: Iterator<Item = i32>,
    {
        let mut sum = 0;
        while let Some(x) = iter.next() {
            sum += x;
        }
        sum
    }
    


  12. Associated Types with Lifetimes

  13. trait DataSource {
        type Item<'a>
        where
            Self: 'a;
    
        fn get_items<'a>(&'a self) -> Box<dyn Iterator<Item = Self::Item<'a>> + 'a>;
    }
    



  14. Associated Constants in Traits

  15. trait Bounded {
        const MIN: i32;
        const MAX: i32;
    
        fn clamp(&self) -> i32;
    }
    
    struct SensorValue(i32);
    
    impl Bounded for SensorValue {
        const MIN: i32 = 0;
        const MAX: i32 = 100;
    
        fn clamp(&self) -> i32 {
            self.0.clamp(Self::MIN, Self::MAX)
        }
    }
    



Phantom Type Parameters in Rust

  1. What Are Phantom Type Parameters?



  2. Why Rust Needs PhantomData



  3. Basic Example: Type-Level Marker

  4. use std::marker::PhantomData;
    
    struct Meters;
    struct Kilometers;
    
    struct Distance<Unit> {
        value: f64,
        _unit: PhantomData<Unit>,
    }
    
    fn main() {
        let d1: Distance<Meters> = Distance { value: 100.0, _unit: PhantomData };
        let d2: Distance<Kilometers> = Distance { value: 2.0, _unit: PhantomData };
    
        // They are NOT interchangeable:
        // let mix = d1 + d2; // compile error unless you define how to add different units
    }
    


  5. Phantom Types for API Safety

  6. use std::marker::PhantomData;
    
    struct Disconnected;
    struct Connected;
    
    struct Network<State> {
        _state: PhantomData<State>,
    }
    
    impl Network<Disconnected> {
        fn connect(self) -> Network<Connected> {
            Network { _state: PhantomData }
        }
    }
    
    impl Network<Connected> {
        fn send(&self, msg: &str) {
            println!("Sending: {}", msg);
        }
    }
    
    fn main() {
        let net = Network<Disconnected> { _state: PhantomData };
        let net = net.connect();  // OK, returns Network<Connected>
        net.send("Hi!");          // Only allowed after connecting
    }
    



  7. Phantom Types for Lifetime Tracking

  8. use std::marker::PhantomData;
    
    struct SliceInfo<'a, T> {
        start: usize,
        end: usize,
        _marker: PhantomData<&'a T>, // expresses lifetime dependency
    }
    
    fn main() {
        let xs = vec![1, 2, 3];
        let info = SliceInfo<'_, i32> {
            start: 0,
            end: 2,
            _marker: PhantomData,
        };
    
        // Rust now knows that 'info' cannot outlive xs, conceptually.
    }
    



  9. Zero-Sized Types (ZSTs)

  10. struct Marker<T> {
        _marker: PhantomData<T>,
    }
    
    fn main() {
        println!("size = {}", std::mem::size_of::<Marker<i32>>()); // prints 0
    }
    




Scoping Rules in Rust

  1. What Is a Scope in Rust?



  2. Variable Lifetime and Scope

  3. fn main() {
        let x = 10; // x comes into scope
    
        {
            let y = 20; // y is valid only in this inner block
            println!("x = {}, y = {}", x, y);
        } // y is dropped here
    
        // println!("{}", y); // ERROR: y does not exist anymore
    } // x is dropped here
    


  4. Shadowing: Redeclaring a Variable Name Inside the Same Scope

  5. let x = 10;
    let x = x + 5;   // shadow old x
    let x = "hello"; // shadow again with new type
    
    let x = 1;
    
    {
        let x = 2; // shadows outer x
        println!("inner x = {}", x);
    }
    
    println!("outer x = {}", x);
    


  6. Ownership and Borrowing Are Scope-Based

  7. let mut s = String::from("hello");
    
    let r = &s; // immutable borrow in scope
    println!("{}", r);
    
    // r is no longer used after here, borrow ends
    
    let mut_ref = &mut s; // OK: previous borrow ended
    mut_ref.push_str(" world");
    


  8. Temporary Scopes: Limiting the Lifetime of Borrows

  9. let mut s = String::from("hello");
    
    {
        let r = &s; // borrow active only inside this block
        println!("{}", r);
    } // borrow ends here
    
    let r2 = &mut s; // now allowed
    r2.push_str(" world");
    


  10. Function Scope and Parameter Lifetimes

  11. fn foo(x: i32) {
        println!("{}", x);
    } // x is dropped here
    

    fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
        if x.len() > y.len() { x } else { y }
    }
    


  12. Scopes and Loops

  13. for i in 0..3 {
        let val = i * 2;
        println!("{}", val);
    }
    // val is not accessible here
    

    while condition() {
        {
            let temp = compute_something();
            println!("{}", temp);
        } // temp dropped each iteration
    }
    


  14. Match Arms Have Independent Scopes

  15. match n {
        0 => {
            let x = 10;
            println!("{}", x);
        }
        1 => {
            // x does not exist here
        }
        _ => {}
    }
    



  16. Scopes in Closures

  17. let mut num = 5;
    
    let add = |x| num + x; // borrow of num
    
    println!("{}", add(3));
    


  18. Scopes and Drop Order

  19. let a = String::from("A");
    let b = String::from("B");
    let c = String::from("C");
    
    // When leaving scope, drop order: c, b, a
    


    {
        let a = String::from("outer");
        {
            let b = String::from("inner");
        } // b dropped here
    } // a dropped here
    


  20. Tight Scopes Help the Borrow Checker

  21. let mut data = vec![1, 2, 3];
    
    {
        let first = &data[0];
        println!("{}", first);
    } // borrow ends earlier
    
    data.push(4); // OK now
    


  22. Lifetimes Tied to Scopes (Very Important!)

  23. let r;              // r has no value yet
    
    {
        let x = 5;
        r = &x;        // ERROR: x does not live long enough
    } // x dropped here
    
    println!("{}", r);
    



Lifetimes in Rust

  1. What Are Lifetimes in Rust?



  2. Why Are Lifetimes Needed?

  3. let r;
    
    {
        let x = 10;
        r = &x;  // ERROR: x does not live long enough
    } // x dropped here
    
    println!("{}", r);
    


  4. How Lifetimes Work: The Basic Rules

  5. fn foo<'a>(x: &'a i32) -> &'a i32 {
        x
    }
    



  6. Lifetime Syntax and Meaning

  7. fn borrow<'a>(x: &'a i32) -> &'a i32 {
        x
    }
    


  8. Multiple Input Lifetimes

  9. fn choose<'a, 'b>(x: &'a str, y: &'b str) -> &'a str {
        x
    }
    


  10. The Famous Example: Returning the Longer String

  11. fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
        if x.len() > y.len() { x } else { y }
    }
    


  12. Lifetime Elision Rules (When You Don’t Need to Write Lifetimes)

  13. // No annotations needed:
    fn identity(x: &i32) -> &i32 {
        x
    }
    
    fn identity<'a>(x: &'a i32) -> &'a i32 {
        x
    }
    


  14. Lifetimes in Structs

  15. struct Holder<'a> {
        value: &'a str,
    }
    
    fn main() {
        let s = String::from("hello");
        let h = Holder { value: &s };
        println!("{}", h.value);
    }
    


  16. Methods and Lifetimes

  17. impl<'a> Holder<'a> {
        fn get(&self) -> &'a str {
            self.value
        }
    }
    


  18. Lifetimes in Traits

  19. trait Logger<'a> {
        fn log(&self) -> &'a str;
    }
    


  20. Static Lifetime 'static

  21. let s: &'static str = "hello world";
    


  22. Lifetimes and Borrow Checker Interaction

  23. let mut s = String::from("hello");
    
    let r1 = &s;
    let r2 = &mut s; // ERROR: cannot borrow mutably while immutably borrowed
    
    println!("{}", r1);
    

    let mut s = String::from("hello");
    
    {
        let r1 = &s;
        println!("{}", r1);
    } // r1 dead here
    
    let r2 = &mut s; // OK
    


  24. Lifetimes in Closures

  25. let s = String::from("hi");
    let closure = || println!("{}", s); // closure borrows s
    closure();
    // s dropped after closure no longer needs it
    


  26. Generic Associated Types (GATs) and Lifetimes

  27. trait DataSource {
        type Iter<'a>: Iterator<Item = &'a str>;
        fn iter<'a>(&'a self) -> Self::Iter<'a>;
    }
    



Borrowing in Rust

  1. What Is Borrowing?



  2. Immutable Borrow: &T

  3. let s = String::from("hello");
    
    let r1 = &s;
    let r2 = &s;
    
    println!("{}, {}", r1, r2); // OK: multiple reads allowed
    


  4. Mutable Borrow: &mut T

  5. let mut s = String::from("hello");
    
    let r = &mut s;
    r.push_str(" world");
    // println!("{}", s); // ERROR: s borrowed mutably
    


  6. The Borrowing Rules (Critical to Understand)



  7. Temporary Scopes Help Borrowing

  8. let mut s = String::from("hello");
    
    {
        let r = &s;
        println!("{}", r);
    } // r ends here
    
    let r2 = &mut s; // now allowed
    r2.push_str(" world");
    


  9. Borrowing in Function Arguments

  10. fn print_len(s: &String) {
        println!("len = {}", s.len());
    }
    
    fn main() {
        let s = String::from("hello");
        print_len(&s);  // Borrowing
        println!("{}", s); // Still own s
    }
    


  11. Mutable Borrow in Functions

  12. fn append_world(s: &mut String) {
        s.push_str(" world");
    }
    
    fn main() {
        let mut s = String::from("hello");
        append_world(&mut s); // mutable borrow
        println!("{}", s);     // "hello world"
    }
    


  13. Borrowing and Return Values

  14. fn bad() -> &i32 {
        let x = 10;
        &x  // ERROR: x does not live long enough
    }
    


  15. Borrowing with Mutable Iteration

  16. let mut data = vec![1, 2, 3];
    
    for x in &data {      // immutable borrow
        println!("{}", x);
    }
    
    for x in &mut data {  // mutable borrow
        *x *= 2;
    }
    


  17. Borrowing and Slices

  18. let nums = vec![1, 2, 3, 4, 5];
    let slice = &nums[1..4]; // borrow a view
    println!("{:?}", slice);
    


  19. Borrowing in Structs

  20. struct Holder<'a> {
        value: &'a str,
    }
    
    fn main() {
        let s = String::from("hello");
        let h = Holder { value: &s };
        println!("{}", h.value);
    }
    


  21. Non-Lexical Lifetimes (NLL)

  22. let mut s = String::from("hello");
    let r = &s;
    println!("{}", r); // r ends here automatically
    
    let r2 = &mut s; // OK now
    r2.push_str("!");
    



Derive in Rust

  1. What Is Derive?



  2. Basic Syntax

  3. #[derive(Debug, Clone, PartialEq)]
    struct Point {
        x: i32,
        y: i32,
    }
    
    fn main() {
        let p1 = Point { x: 1, y: 2 };
        let p2 = p1.clone();
    
        println!("{:?}", p1);       // Debug
        println!("{}", p1 == p2);   // PartialEq
    }
    


  4. Common Derivable Traits (Standard Library)

  5. Trait Purpose
    Debug Enables {:?} formatting for printing
    Clone Allows explicit duplication via .clone()
    Copy Enables implicit bitwise copy (requires Clone)
    PartialEq Enables == and != comparison
    Eq Marks full equivalence (requires PartialEq)
    PartialOrd Enables <, >, <=, >= comparison
    Ord Total ordering (requires Eq + PartialOrd)
    Hash Allows use as key in HashMap / HashSet
    Default Provides a default value via Default::default()


  6. The Debug Trait

  7. #[derive(Debug)]
    struct User {
        name: String,
        age: u32,
    }
    
    fn main() {
        let user = User {
            name: String::from("Alice"),
            age: 30,
        };
    
        println!("{:?}", user);   // User { name: "Alice", age: 30 }
        println!("{:#?}", user);  // Pretty-printed
    }
    


  8. The Clone and Copy Traits

  9. #[derive(Debug, Clone, Copy)]
    struct Point {
        x: i32,
        y: i32,
    }
    
    fn main() {
        let p1 = Point { x: 1, y: 2 };
        let p2 = p1;  // Copy, not move
    
        println!("{:?} {:?}", p1, p2); // Both valid
    }
    


  10. The PartialEq and Eq Traits

  11. #[derive(Debug, PartialEq, Eq)]
    struct Id(u64);
    
    fn main() {
        let a = Id(42);
        let b = Id(42);
        let c = Id(99);
    
        println!("{}", a == b); // true
        println!("{}", a == c); // false
    }
    


  12. The PartialOrd and Ord Traits

  13. #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
    struct Version {
        major: u32,
        minor: u32,
        patch: u32,
    }
    
    fn main() {
        let v1 = Version { major: 1, minor: 2, patch: 0 };
        let v2 = Version { major: 1, minor: 3, patch: 0 };
    
        println!("{}", v1 < v2); // true
    }
    


  14. The Hash Trait

  15. use std::collections::HashSet;
    
    #[derive(Debug, PartialEq, Eq, Hash)]
    struct Email(String);
    
    fn main() {
        let mut emails = HashSet::new();
        emails.insert(Email(String::from("a@example.com")));
        emails.insert(Email(String::from("b@example.com")));
    
        println!("{:?}", emails);
    }
    


  16. The Default Trait

  17. #[derive(Debug, Default)]
    struct Config {
        debug: bool,       // defaults to false
        timeout: u32,      // defaults to 0
        name: String,      // defaults to ""
    }
    
    fn main() {
        let cfg = Config::default();
        println!("{:#?}", cfg);
    }
    


  18. Derive for Enums

  19. #[derive(Debug, Clone, PartialEq)]
    enum Status {
        Pending,
        Active { since: u64 },
        Closed(String),
    }
    
    fn main() {
        let s1 = Status::Active { since: 1000 };
        let s2 = s1.clone();
    
        println!("{:?}", s1 == s2); // true
    }
    


  20. Derive with Generics

  21. #[derive(Debug, Clone, PartialEq)]
    struct Wrapper<T> {
        value: T,
    }
    
    fn main() {
        let w1 = Wrapper { value: 42 };
        let w2 = w1.clone();
    
        println!("{:?}", w1 == w2); // true
    }
    


  22. When Derive Fails: Manual Implementation

  23. struct Counter {
        count: u32,
        cache: Vec<u32>,  // Ignore in equality check
    }
    
    impl PartialEq for Counter {
        fn eq(&self, other: &Self) -> bool {
            self.count == other.count  // Ignore cache
        }
    }
    


  24. Multiple Derives at Once

  25. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
    struct Priority(u8);
    


  26. Third-Party Derive Macros

  27. use serde::{Serialize, Deserialize};
    
    #[derive(Debug, Serialize, Deserialize)]
    struct Person {
        name: String,
        age: u32,
    }