InterviewPitch
Rust interview questions

Rust Interview Questions with Answers

Most Asked Rust Interview Questions for Software Engineer Roles

100+ QuestionsDetailed AnswersCode ExamplesUpdated for 2026

Introduction

Rust is a modern systems programming language that has taken the tech world by storm. With its unique ownership model, it guarantees memory safety and thread safety without the need for a garbage collector – a feat that few languages can match. Rust is widely used in systems programming, embedded systems, game engines, and WebAssembly development, making it one of the most sought‑after skills in the industry. This comprehensive guide brings you 100+ carefully curated Rust interview questions and answers, covering everything from beginner fundamentals to advanced concepts. You'll master variables, data types, functions, ownership, borrowing, lifetimes, structs, enums, traits, error handling (Result/Option), concurrency (threads and channels), asynchronous programming with Tokio, smart pointers (Box, Rc, Arc, RefCell, Weak), unsafe code, FFI with C, serialization with Serde, and real‑world Rust development scenarios. Whether you're aiming for a systems programming role, an embedded engineer position, or a backend job using Rust, this question bank will help you solidify your understanding and give you the confidence to tackle even the toughest technical challenges. Start practicing now and join the growing community of Rustaceans who are shaping the future of software development.

Why Rust?

  • Memory safety without garbage collection – prevents null pointer dereferences and data races
  • Zero-cost abstractions – high-level features without performance overhead
  • Fearless concurrency – thread safety guaranteed at compile time
  • Growing ecosystem and strong community – used at Mozilla, Dropbox, Cloudflare, and more
  • Increasingly popular for system programming, embedded, and WebAssembly
  • Consistently ranked as one of the most loved programming languages

Most Asked Rust Interview Questions

Beginner
1. What is Rust?

Rust is a systems programming language focused on safety, speed, and concurrency. It guarantees memory safety without a garbage collector.

  • Memory safe: Ownership system prevents memory bugs
  • Zero-cost abstractions: High-level features without runtime overhead
  • Concurrent: Fearless concurrency
  • No garbage collector: Manual memory management with safety
  • Systems language: Can write OS kernels, embedded systems, web servers
rust
// Hello World in Rust
fn main() {
    println!("Hello, World!");
}
Beginner
2. How to declare variables in Rust?

Variables in Rust are immutable by default. Use let for immutable and let mut for mutable variables.

  • Immutable: let x = 10
  • Mutable: let mut y = 20
  • Type inference: let z = 42
  • Explicit types: let a: i32 = 10
  • Constants: const PI: f64 = 3.14159
  • Shadowing: let x = 5; let x = x + 1
rust
// Variables in Rust
fn main() {
    // Immutable variable (default)
    let immutable_var = "Hello";
    
    // Mutable variable
    let mut mutable_var = "World";
    mutable_var = "Rust";
    
    // Type inference
    let inferred = 42;
    
    // Explicit type
    let explicit: i32 = 10;
    
    // Constants
    const PI: f64 = 3.14159;
    
    // Shadowing
    let x = 5;
    let x = x + 1;
    
    // Display
    println!("{}", immutable_var);
    println!("{}", mutable_var);
    println!("{}", inferred);
    println!("{}", explicit);
    println!("{}", PI);
    println!("{}", x);
}
Beginner
3. What are the data types in Rust?

Rust provides scalar and compound data types including integers, floats, booleans, characters, arrays, tuples, and more.

  • Integer: i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize
  • Floating point: f32, f64
  • Boolean: bool
  • Character: char
  • String: String, &str
  • Array: [T; N] (fixed size)
  • Tuple: (T1, T2, T3)
  • Vector: Vec<T> (dynamic size)
rust
// Data Types in Rust
fn main() {
    // Integer types
    let signed_8: i8 = -128;
    let unsigned_8: u8 = 255;
    let signed_32: i32 = -1000;
    let unsigned_64: u64 = 1000;
    let default_int = 42; // i32 by default
    
    // Floating point types
    let float_32: f32 = 3.14;
    let float_64: f64 = 3.14159;
    let default_float = 3.14; // f64 by default
    
    // Boolean
    let is_rust_awesome: bool = true;
    let is_false = false;
    
    // Character (Unicode)
    let character: char = 'A';
    let emoji: char = '🚀';
    let unicode: char = '中';
    
    // String types
    let string_literal: &str = "Hello, world!";
    let heap_string: String = String::from("Hello");
    let mut mutable_string = String::new();
    mutable_string.push_str("Rust");
    
    // Arrays (fixed size)
    let array: [i32; 5] = [1, 2, 3, 4, 5];
    let first = array[0];
    let repeated = [0; 10]; // [0, 0, ..., 0] (10 elements)
    
    // Tuples (fixed size, heterogeneous)
    let tuple: (i32, f64, char) = (42, 3.14, 'A');
    let (x, y, z) = tuple; // destructuring
    let first_element = tuple.0;
    
    // Vectors (dynamic size)
    let mut vector: Vec<i32> = vec![1, 2, 3];
    vector.push(4);
    let second = vector[1];
    
    // Type inference
    let inferred_int = 100; // i32
    let inferred_float = 3.14; // f64
    let inferred_bool = true; // bool
    
    println!("Integers: {}, {}, {}", signed_8, unsigned_32, default_int);
    println!("Floats: {}, {}", float_32, float_64);
    println!("Boolean: {}", is_rust_awesome);
    println!("Character: {}", character);
    println!("String: {}", heap_string);
    println!("Array: {:?}", array);
    println!("Tuple: {:?}", tuple);
    println!("Vector: {:?}", vector);
}
Beginner
4. How to define functions in Rust?

Functions in Rust are defined with the fn keyword. They can have parameters and return values.

  • Basic: fn add(a: i32, b: i32) -> i32 { a + b }
  • No return: fn print() { println!("Hello") }
  • Multiple returns: fn divide(a: i32, b: i32) -> (i32, i32)
  • Generic functions: fn swap<T>(a: T, b: T) -> (T, T)
  • Closures: |a, b| a + b
rust
// Functions in Rust
fn main() {
    // Call functions
    let sum = add(5, 3);
    println!("Sum: {}", sum);
    
    let result = divide(10, 3);
    println!("Quotient: {}, Remainder: {}", result.0, result.1);
    
    let (a, b) = swap(10, 20);
    println!("Swapped: {}, {}", a, b);
    
    // Closure example
    let add_closure = |a, b| a + b;
    println!("Closure sum: {}", add_closure(5, 3));
    
    // Higher-order function
    let doubled = apply_twice(3, |x| x * 2);
    println!("Doubled twice: {}", doubled);
}

// Basic function with return value
fn add(a: i32, b: i32) -> i32 {
    a + b // Implicit return (no semicolon)
}

// Function with no return value (returns unit type ())
fn print_message() {
    println!("Hello from Rust!");
}

// Function returning multiple values using tuple
fn divide(a: i32, b: i32) -> (i32, i32) {
    let quotient = a / b;
    let remainder = a % b;
    (quotient, remainder)
}

// Generic function
fn swap<T>(a: T, b: T) -> (T, T) {
    (b, a)
}

// Function with explicit return (using return keyword)
fn is_even(num: i32) -> bool {
    if num % 2 == 0 {
        return true;
    }
    false
}

// Higher-order function (takes closure as parameter)
fn apply_twice<F>(x: i32, f: F) -> i32 
where F: Fn(i32) -> i32 {
    f(f(x))
}
Beginner
5. What is ownership in Rust?

Ownership is Rust's core memory safety rule. Every value has a single owner, and when the owner goes out of scope, the value is dropped. Ownership can be moved (transferred) or borrowed.

  • Each value has exactly one owner
  • Move: transferring ownership (e.g., assignment, passing to function)
  • Clone: deep copy for heap data
  • Drop: automatic cleanup when owner goes out of scope
rust
// Arrays and Vectors in Rust
fn main() {
    // Array (fixed size)
    let numbers: [i32; 5] = [1, 2, 3, 4, 5];
    let strings: [&str; 3] = ["Apple", "Banana", "Orange"];
    let mixed: [i32; 3] = [1, 2, 3];
    
    // Access and modify (arrays are immutable by default)
    println!("{}", numbers[2]);  // Access element
    // numbers[2] = 10; // Not allowed if not mutable
    
    // Array operations
    println!("Length: {}", numbers.len());
    
    // Iteration
    for num in numbers.iter() {
        println!("{}", num);
    }
    
    // Vector (dynamic array)
    let mut vec_numbers: Vec<i32> = vec![1, 2, 3, 4, 5];
    vec_numbers.push(6);
    vec_numbers.pop();
    vec_numbers[2] = 10;
    
    // Vector operations
    let doubled: Vec<i32> = vec_numbers.iter().map(|x| x * 2).collect();
    let filtered: Vec<i32> = vec_numbers.iter().filter(|&&x| x > 2).cloned().collect();
    let sum: i32 = vec_numbers.iter().sum();
    
    println!("{:?}", doubled);
    println!("{:?}", filtered);
    println!("{}", sum);
}
Beginner
6. How does borrowing work in Rust?

Borrowing allows you to reference a value without taking ownership. References are either immutable (&T) or mutable (&mut T). The borrow checker enforces rules to prevent data races.

  • Immutable reference: &T – can have multiple readers
  • Mutable reference: &mut T – exclusive access
  • Rule 1: Either one mutable reference or any number of immutable ones
  • Rule 2: References must always be valid (no dangling references)
rust
// Collections in Rust
use std::collections::{HashMap, HashSet, VecDeque};

fn main() {
    // Vector (List)
    let mut vec: Vec<i32> = vec![1, 2, 3, 4, 5];
    vec.push(6);
    vec.remove(1);
    
    // HashSet (Set)
    let mut set: HashSet<i32> = HashSet::new();
    set.insert(1);
    set.insert(2);
    set.insert(3);
    set.insert(3);  // Won't add duplicate
    
    // HashMap (Dictionary)
    let mut map: HashMap<&str, &str> = HashMap::new();
    map.insert("key1", "value1");
    map.insert("key2", "value2");
    map.remove("key1");
    
    // VecDeque (Double-ended queue)
    let mut deque: VecDeque<i32> = VecDeque::new();
    deque.push_back(1);
    deque.push_front(0);
    deque.pop_back();
    deque.pop_front();
    
    // Collection operations
    let numbers = vec![1, 2, 3, 4, 5, 6];
    let evens: Vec<i32> = numbers.iter().filter(|&&x| x % 2 == 0).cloned().collect();
    let doubled: Vec<i32> = numbers.iter().map(|&x| x * 2).collect();
    let sum: i32 = numbers.iter().sum();
    
    println!("{:?}", evens);
    println!("{:?}", doubled);
    println!("{}", sum);
}
Beginner
7. What is the difference between String and &str?

String is a growable, heap-allocated string type. &str is a string slice – a view into a string that is typically immutable and can be stack-allocated or part of a String.

  • String: Owned, mutable, heap-allocated
  • &str: Borrowed, immutable, fixed-size view
  • Conversion: String::from("hello"), my_string.as_str()
  • Usage: &str for function parameters, String for owned data
rust
// Structs (Data Classes) in Rust
#[derive(Debug, Clone)]
struct Person {
    name: String,
    age: u32,
    city: String,
}

impl Person {
    // Constructor
    fn new(name: String, age: u32, city: String) -> Self {
        Person {
            name,
            age,
            city,
        }
    }
    
    // Method
    fn greet(&self) -> String {
        format!("Hello, my name is {}", self.name)
    }
    
    // Method with default values
    fn with_defaults(name: String, age: u32) -> Self {
        Person {
            name,
            age,
            city: String::from("Unknown"),
        }
    }
}

fn main() {
    let person1 = Person::new(String::from("Alice"), 25, String::from("NYC"));
    let person2 = person1.clone();
    
    // Update using struct update syntax
    let person3 = Person {
        age: 26,
        ..person2
    };
    
    println!("Name: {}", person1.name);
    println!("Age: {}", person1.age);
    println!("City: {}", person1.city);
    println!("{}", person1.greet());
    println!("{:?}", person3);
}
Beginner
8. What are slices in Rust?

A slice is a reference to a contiguous sequence of elements in a collection (like an array or vector). Slices are immutable by default and can be created using the range syntax &[start..end].

  • Array slice: &[i32]
  • String slice: &str (already a slice)
  • Creation: &arr[1..4] (excludes end)
  • Benefits: No copying, safe access to parts of data
rust
// Enums (Sealed Classes) in Rust
#[derive(Debug)]
enum Result<T, E> {
    Success(T),
    Error(E),
    Loading,
}

#[derive(Debug)]
enum Shape {
    Circle(f64),
    Rectangle(f64, f64),
    Point,
}

impl Shape {
    fn area(&self) -> f64 {
        match self {
            Shape::Circle(radius) => std::f64::consts::PI * radius * radius,
            Shape::Rectangle(width, height) => width * height,
            Shape::Point => 0.0,
        }
    }
}

// Enum with associated data
#[derive(Debug)]
enum Payment {
    Cash(f64),
    CreditCard { number: String, expiry: String },
    PayPal { email: String },
}

fn handle_payment(payment: Payment) -> String {
    match payment {
        Payment::Cash(amount) => format!("Cash amount: $\{:.2}", amount),
        Payment::CreditCard { number, expiry } => format!("Card: {}, Expiry: {}", number, expiry),
        Payment::PayPal { email } => format!("PayPal: {}", email),
    }
}

fn main() {
    let result = Result::Success(String::from("Data loaded"));
    let shape = Shape::Circle(5.0);
    let payment = Payment::CreditCard {
        number: String::from("1234-5678-9012-3456"),
        expiry: String::from("12/25"),
    };
    
    println!("{:?}", result);
    println!("Area: {}", shape.area());
    println!("{}", handle_payment(payment));
}
Beginner
9. How to define methods on structs?

Methods are defined in an impl block for the struct. They can take &self, &mut self, or self as the first parameter.

  • Immutable: fn method(&self) { }
  • Mutable: fn method(&mut self) { }
  • Ownership: fn method(self) { } (consumes the struct)
  • Associated functions: fn new() -> Self (no self)
rust
// Null Safety in Rust (Option and Result)
fn main() {
    // Option type (null safety)
    let nullable_string: Option<String> = Some(String::from("Hello"));
    let null_string: Option<String> = None;
    
    // Safe access with match
    match nullable_string {
        Some(s) => println!("String is: {}", s),
        None => println!("String is null"),
    }
    
    // Unwrap with default
    let length = nullable_string.as_ref().map_or(0, |s| s.len());
    println!("Length: {}", length);
    
    // Elvis operator equivalent using unwrap_or
    let value = null_string.unwrap_or(String::from("default"));
    println!("Value: {}", value);
    
    // Optional chaining using and_then
    let result = nullable_string
        .as_ref()
        .and_then(|s| Some(s.len()));
    println!("Result: {:?}", result);
    
    // If let for simple cases
    if let Some(s) = nullable_string {
        println!("If let: {}", s);
    }
    
    // Result type for operations that can fail
    fn divide(a: i32, b: i32) -> Result<i32, &'static str> {
        if b == 0 {
            Err("Division by zero")
        } else {
            Ok(a / b)
        }
    }
    
    match divide(10, 2) {
        Ok(result) => println!("Result: {}", result),
        Err(e) => println!("Error: {}", e),
    }
}
Beginner
10. What are enums and pattern matching in Rust?

Enums define a type that can be one of several variants. Pattern matching (match) destructures enums and handles each variant, ensuring exhaustive handling.

  • Enum definition: enum IpAddr { V4(u8, u8, u8, u8), V6(String) }
  • Match: match value { Variant1 => ..., _ => ... }
  • Exhaustive: Compiler checks all variants are handled
  • if let: concise matching for a single pattern
rust
// Control Flow in Rust
fn main() {
    // If-else
    let age = 25;
    let status = if age < 18 { "Minor" } else { "Adult" };
    println!("{}", status);
    
    // Match (switch replacement)
    let grade = 'A';
    let result = match grade {
        'A' => "Excellent",
        'B' => "Good",
        'C' => "Fair",
        _ => "Needs Improvement",
    };
    println!("{}", result);
    
    // Match with ranges
    let score = 85;
    let grade2 = match score {
        90..=100 => "A",
        80..=89 => "B",
        70..=79 => "C",
        _ => "F",
    };
    println!("{}", grade2);
    
    // For loop
    for i in 0..5 {
        println!("{}", i);
    }
    
    // For loop with step
    for i in (1..10).step_by(2) {
        println!("{}", i);
    }
    
    // For loop descending
    for i in (0..10).rev() {
        println!("{}", i);
    }
    
    // While loop
    let mut i = 0;
    while i < 5 {
        println!("{}", i);
        i += 1;
    }
    
    // Loop (infinite loop with break)
    let mut i = 0;
    loop {
        println!("{}", i);
        i += 1;
        if i >= 5 {
            break;
        }
    }
}
Beginner
11. What is Option and Result in Rust?

Option represents an optional value – either Some(T) or None. Result represents an operation that can succeed (Ok(T)) or fail (Err(E)). They are used extensively for error handling and nullable values.

  • Option: enum Option<T> { Some(T), None }
  • Result: enum Result<T, E> { Ok(T), Err(E) }
  • Methods: unwrap(), expect(), unwrap_or(), ? operator
  • Use: ? operator propagates errors
rust
// Traits and Inheritance in Rust
// Base trait
trait Animal {
    fn name(&self) -> &str;
    fn make_sound(&self) -> String;
    
    // Default implementation
    fn greet(&self) -> String {
        format!("Hello, I'm {}", self.name())
    }
}

// Dog struct
struct Dog {
    name: String,
    breed: String,
}

impl Dog {
    fn new(name: &str, breed: &str) -> Self {
        Dog {
            name: String::from(name),
            breed: String::from(breed),
        }
    }
}

impl Animal for Dog {
    fn name(&self) -> &str {
        &self.name
    }
    
    fn make_sound(&self) -> String {
        String::from("Woof!")
    }
}

// Cat struct
struct Cat {
    name: String,
    color: String,
}

impl Animal for Cat {
    fn name(&self) -> &str {
        &self.name
    }
    
    fn make_sound(&self) -> String {
        String::from("Meow!")
    }
}

// Trait inheritance
trait Flyable {
    fn fly(&self) -> String;
}

trait Swimmable {
    fn swim(&self) -> String;
}

struct Duck {
    name: String,
}

impl Flyable for Duck {
    fn fly(&self) -> String {
        String::from("Flying")
    }
}

impl Swimmable for Duck {
    fn swim(&self) -> String {
        String::from("Swimming")
    }
}

fn main() {
    let dog = Dog::new("Rex", "German Shepherd");
    let cat = Cat {
        name: String::from("Whiskers"),
        color: String::from("Black"),
    };
    let duck = Duck {
        name: String::from("Donald"),
    };
    
    println!("{} says: {}", dog.name(), dog.make_sound());
    println!("{} says: {}", cat.name(), cat.make_sound());
    println!("{}", dog.greet());
    println!("{}", duck.fly());
    println!("{}", duck.swim());
}
Beginner
12. How to handle errors with Result?

Result is used for recoverable errors. You can handle errors with match, unwrap_or_else, or the ? operator to propagate errors to the caller.

  • match: match result { Ok(v) => v, Err(e) => ... }
  • ?: let value = do_something()?; (propagates error)
  • unwrap: panic on error (use sparingly)
  • Custom errors: define your own error types
rust
// Properties/Fields in Rust
struct Person {
    name: String,
    age: u32,
    email: String,
}

impl Person {
    // Constructor
    fn new(name: String, age: u32, email: String) -> Self {
        Person { name, age, email }
    }
    
    // Getter
    fn name(&self) -> &str {
        &self.name
    }
    
    // Getter with transformation
    fn age(&self) -> u32 {
        self.age
    }
    
    // Setter with validation
    fn set_age(&mut self, age: u32) -> Result<(), &'static str> {
        if age < 0 {
            return Err("Age cannot be negative");
        }
        self.age = age;
        Ok(())
    }
    
    // Computed property
    fn full_name(&self) -> String {
        format!("{} (Age: {})", self.name, self.age)
    }
    
    // Lazy initialization pattern
    fn expensive_data(&self) -> &str {
        // In real code, this would compute once and cache
        "Expensive Result"
    }
}

// Using lazy_static or once_cell for lazy properties
use std::cell::OnceCell;

struct LazyPerson {
    name: String,
    expensive_data: OnceCell<String>,
}

impl LazyPerson {
    fn new(name: String) -> Self {
        LazyPerson {
            name,
            expensive_data: OnceCell::new(),
        }
    }
    
    fn get_expensive_data(&self) -> &str {
        self.expensive_data.get_or_init(|| {
            println!("Computing expensive data...");
            String::from("Expensive Result")
        })
    }
}

fn main() {
    let mut person = Person::new(String::from("Alice"), 25, String::from("alice@example.com"));
    
    println!("Name: {}", person.name());
    println!("Age: {}", person.age());
    println!("Full name: {}", person.full_name());
    
    match person.set_age(26) {
        Ok(()) => println!("Age updated to: {}", person.age()),
        Err(e) => println!("Error: {}", e),
    }
    
    let lazy_person = LazyPerson::new(String::from("Bob"));
    println!("{}", lazy_person.get_expensive_data());
    println!("{}", lazy_person.get_expensive_data()); // Cached
}
Beginner
13. What are traits and generics in Rust?

Traits define shared behavior (similar to interfaces). Generics allow writing code that works with multiple types. Traits can be used as bounds on generic parameters.

  • Trait definition: trait Summary { fn summarize(&self) -> String; }
  • Implement: impl Summary for NewsArticle { ... }
  • Generic function: fn print<T: Display>(item: T) { ... }
  • Derived traits: #[derive(Debug, Clone)]
rust
// Associated Functions and Constants in Rust
struct MyClass {
    value: i32,
}

impl MyClass {
    // Associated constant
    const TAG: &'static str = "MyClass";
    
    // Associated function (similar to static method)
    fn new(value: i32) -> Self {
        MyClass { value }
    }
    
    // Factory method
    fn create() -> Self {
        MyClass { value: 0 }
    }
    
    // Instance method
    fn get_value(&self) -> i32 {
        self.value
    }
    
    // Method that modifies self
    fn set_value(&mut self, value: i32) {
        self.value = value;
    }
}

// Singleton pattern using lazy_static
use std::sync::OnceLock;

struct Config {
    api_url: String,
    timeout: u32,
}

impl Config {
    fn new() -> Self {
        Config {
            api_url: String::from("https://api.example.com"),
            timeout: 5000,
        }
    }
    
    fn instance() -> &'static Config {
        static INSTANCE: OnceLock<Config> = OnceLock::new();
        INSTANCE.get_or_init(|| Config::new())
    }
}

fn main() {
    println!("{}", MyClass::TAG);
    
    let mut obj = MyClass::new(42);
    println!("Value: {}", obj.get_value());
    
    obj.set_value(100);
    println!("Updated value: {}", obj.get_value());
    
    let config = Config::instance();
    println!("API URL: {}", config.api_url);
    println!("Timeout: {}", config.timeout);
}
Beginner
14. What are closures in Rust?

Closures are anonymous functions that can capture variables from their environment. They are defined with |params| { body } and implement one of the Fn, FnMut, or FnOnce traits.

  • Capture: Can take ownership (move), borrow mutably, or immutably
  • Traits: Fn (immutable borrow), FnMut (mutable borrow), FnOnce (consumes)
  • Usage: let add = |x, y| x + y;
  • Move: let f = move |x| x + captured;
rust
// Error Handling in Rust
use std::fs::File;
use std::io::{self, Read};

// Custom error type
#[derive(Debug)]
enum MyError {
    InvalidAge,
    IoError(io::Error),
}

impl From<io::Error> for MyError {
    fn from(error: io::Error) -> Self {
        MyError::IoError(error)
    }
}

// Function that returns Result
fn divide(a: i32, b: i32) -> Result<i32, &'static str> {
    if b == 0 {
        return Err("Division by zero");
    }
    Ok(a / b)
}

// Function with custom error
fn validate_age(age: i32) -> Result<(), MyError> {
    if age < 0 || age > 150 {
        return Err(MyError::InvalidAge);
    }
    Ok(())
}

// Function with ? operator
fn read_file() -> Result<String, MyError> {
    let mut file = File::open("test.txt")?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    Ok(contents)
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Using match
    match divide(10, 2) {
        Ok(result) => println!("Result: {}", result),
        Err(e) => println!("Error: {}", e),
    }
    
    // Using unwrap_or
    let result = divide(10, 0).unwrap_or(0);
    println!("Result: {}", result);
    
    // Using ? operator
    let result = divide(10, 2)?;
    println!("Result: {}", result);
    
    // Using if let
    if let Ok(result) = divide(10, 2) {
        println!("Result: {}", result);
    }
    
    // Custom error handling
    match validate_age(200) {
        Ok(()) => println!("Age is valid"),
        Err(e) => println!("Error: {:?}", e),
    }
    
    // Propagating errors
    match read_file() {
        Ok(contents) => println!("File contents: {}", contents),
        Err(e) => println!("Error reading file: {:?}", e),
    }
    
    Ok(())
}

// Example with payment enum
enum Payment {
    Cash(f64),
    CreditCard { number: String, expiry: String },
    PayPal { email: String },
}

fn handle_payment(payment: Payment) -> String {
    match payment {
        Payment::Cash(amount) => format!("Cash amount: $\{:.2}", amount),
        Payment::CreditCard { number, expiry } => format!("Card: {}, Expiry: {}", number, expiry),
        Payment::PayPal { email } => format!("PayPal: {}", email),
    }
}
Beginner
15. What are iterators in Rust?

Iterators provide a lazy way to process sequences of values. They implement the Iterator trait and can be combined with adapters like map, filter, fold.

  • Creation: vec.iter(), (0..10).into_iter()
  • Adapters: map, filter, take, skip (lazy)
  • Consumers: collect(), fold(), sum() (eager)
  • Lazy: Iterators are lazy – nothing happens until consumed
rust
// Closures (Lambdas) in Rust
fn main() {
    // Basic closure
    let square = |x: i32| x * x;
    
    // Closure with multiple parameters
    let add = |a: i32, b: i32| a + b;
    
    // Closure with multiple lines
    let complex = |x: i32| {
        let y = x * 2;
        y + 10
    };
    
    // Higher-order function
    fn operate<F>(a: i32, b: i32, operation: F) -> i32
    where
        F: Fn(i32, i32) -> i32,
    {
        operation(a, b)
    }
    
    // Closure capturing environment
    let factor = 2;
    let multiply = |x: i32| x * factor;
    
    // Returning closure from function
    fn get_multiplier(factor: i32) -> impl Fn(i32) -> i32 {
        move |x| x * factor
    }
    
    // Using closures with iterators
    let numbers = vec![1, 2, 3, 4, 5];
    let doubled: Vec<i32> = numbers.iter().map(|&x| x * 2).collect();
    let filtered: Vec<i32> = numbers.iter().filter(|&&x| x > 2).cloned().collect();
    
    println!("Square: {}", square(5));
    println!("Add: {}", add(5, 3));
    println!("Complex: {}", complex(5));
    println!("Operate: {}", operate(6, 7, |a, b| a * b));
    println!("Multiply: {}", multiply(5));
    
    let double = get_multiplier(2);
    println!("Double: {}", double(5));
    
    println!("Doubled: {:?}", doubled);
    println!("Filtered: {:?}", filtered);
}
Beginner
16. How to use vectors and collections in Rust?

Vec<T> is a growable, heap-allocated array. Other collections include HashMap, HashSet, BTreeMap, and LinkedList. They are part of the standard library.

  • Vector: let mut v: Vec<i32> = Vec::new();
  • Push: v.push(5);
  • Access: v[0] or v.get(0) (returns Option)
  • Iterate: for x in &v { ... }
rust
// Scope Functions in Rust
// Rust doesn't have built-in scope functions like Kotlin
// but we can use closures and patterns

struct Person {
    name: String,
    age: u32,
    city: String,
}

fn main() {
    // let - execute block (using closure)
    let person = Person {
        name: String::from("Alice"),
        age: 25,
        city: String::from("NYC"),
    };
    
    // Using a closure for scope
    let result = {
        let name = &person.name;
        let age = person.age;
        println!("Name: {}", name);
        person.age + 1
    };
    println!("Result: {}", result);
    
    // apply - configure object (using with)
    let updated_person = {
        let mut p = Person {
            name: person.name.clone(),
            age: person.age,
            city: person.city.clone(),
        };
        p.age = 26;
        p.city = String::from("SF");
        p
    };
    
    // also - perform additional operations
    let numbers = vec![1, 2, 3];
    let processed = {
        let mut temp = numbers.clone();
        println!("Before: {:?}", temp);
        temp.push(4);
        println!("After: {:?}", temp);
        temp
    };
    
    // take-if equivalent using Option
    fn take_if<T, F>(value: T, predicate: F) -> Option<T>
    where
        F: Fn(&T) -> bool,
    {
        if predicate(&value) {
            Some(value)
        } else {
            None
        }
    }
    
    let adult = take_if(25, |&age| age >= 18);
    println!("Adult: {:?}", adult);
}
Beginner
17. How to use HashMaps in Rust?

HashMap<K, V> stores key-value pairs with fast lookups. Keys must implement Eq and Hash. They are useful for counting, caching, and mapping relationships.

  • Create: use std::collections::HashMap;
  • Insert: map.insert(key, value);
  • Get: map.get(&key) returns Option<&V>
  • Entry API: map.entry(key).or_insert(default)
rust
// Extension Traits in Rust
// Rust uses extension traits to add methods to existing types

// String extensions
trait StringExt {
    fn is_email(&self) -> bool;
    fn add_prefix(&self, prefix: &str) -> String;
    fn word_count(&self) -> usize;
}

impl StringExt for String {
    fn is_email(&self) -> bool {
        self.contains('@') && self.contains('.')
    }
    
    fn add_prefix(&self, prefix: &str) -> String {
        format!("{}{}", prefix, self)
    }
    
    fn word_count(&self) -> usize {
        self.split_whitespace().count()
    }
}

impl StringExt for str {
    fn is_email(&self) -> bool {
        self.contains('@') && self.contains('.')
    }
    
    fn add_prefix(&self, prefix: &str) -> String {
        format!("{}{}", prefix, self)
    }
    
    fn word_count(&self) -> usize {
        self.split_whitespace().count()
    }
}

// Numeric extensions
trait NumberExt {
    fn is_even(&self) -> bool;
    fn is_odd(&self) -> bool;
}

impl NumberExt for i32 {
    fn is_even(&self) -> bool {
        self % 2 == 0
    }
    
    fn is_odd(&self) -> bool {
        self % 2 != 0
    }
}

// List extensions
trait ListExt<T> {
    fn second_or_none(&self) -> Option<&T>;
}

impl<T> ListExt<T> for Vec<T> {
    fn second_or_none(&self) -> Option<&T> {
        if self.len() >= 2 {
            Some(&self[1])
        } else {
            None
        }
    }
}

fn main() {
    let email = String::from("test@example.com");
    println!("{}", email.is_email());
    
    let greeting = String::from("Hello").add_prefix("Greeting: ");
    println!("{}", greeting);
    
    println!("{}", 5.is_even());
    println!("{}", 5.word_count());
    
    let numbers = vec![1, 2, 3];
    println!("{:?}", numbers.second_or_none());
}
Beginner
18. What are match expressions in Rust?

match is a powerful control flow construct that compares a value against a series of patterns and executes code based on which pattern matches. It is exhaustive – all possible values must be covered.

  • Syntax: match value { Pattern1 => expr1, Pattern2 => expr2, _ => default }
  • Patterns: literals, variables, wildcards, ranges, destructuring
  • Exhaustive: compiler checks all cases
  • if guard: Pattern if condition => ...
rust
// Type Aliases in Rust
// Type aliases for complex types
type Operation = Box<dyn Fn(i32, i32) -> i32>;
type UserMap = std::collections::HashMap<String, (String, i32)>;
type UserId = u64;
type UserName = String;
type ResultCallback = Box<dyn Fn(String)>;

// Using type aliases
fn execute<F>(op: F, a: i32, b: i32) -> i32
where
    F: Fn(i32, i32) -> i32,
{
    op(a, b)
}

// Function type alias
type OperationFn = fn(i32, i32) -> i32;

fn add(a: i32, b: i32) -> i32 {
    a + b
}

fn multiply(a: i32, b: i32) -> i32 {
    a * b
}

// Tuple type alias
type User = (String, i32);

fn main() {
    // Using Operation type
    let add_op: Operation = Box::new(|a, b| a + b);
    let multiply_op: Operation = Box::new(|a, b| a * b);
    
    println!("{}", execute(*add_op, 5, 3));
    println!("{}", execute(*multiply_op, 5, 3));
    
    // Using OperationFn type
    let add_fn: OperationFn = add;
    let multiply_fn: OperationFn = multiply;
    
    println!("{}", add_fn(5, 3));
    println!("{}", multiply_fn(5, 3));
    
    // Using UserMap type
    let mut users: UserMap = std::collections::HashMap::new();
    users.insert(String::from("user1"), (String::from("Alice"), 25));
    users.insert(String::from("user2"), (String::from("Bob"), 30));
    
    if let Some((name, age)) = users.get("user1") {
        println!("User1: {} ({})", name, age);
    }
    
    // Using User type
    let user: User = (String::from("Alice"), 25);
    println!("User: {}, {}", user.0, user.1);
}
Beginner
19. What are if let and while let in Rust?

if let is a concise way to match a single pattern. while let loops while a pattern matches. They are syntactic sugar for match when you only care about one variant.

  • if let: if let Some(x) = optional { ... }
  • while let: while let Some(x) = iterator.next() { ... }
  • else: if let ... else { ... }
  • Usage: Reduce boilerplate for single-pattern matching
rust
// Inline Functions in Rust
// Rust uses inline attribute for performance optimization

// Inline function
#[inline]
fn square(x: i32) -> i32 {
    x * x
}

// Inline always
#[inline(always)]
fn add(a: i32, b: i32) -> i32 {
    a + b
}

// Inline never
#[inline(never)]
fn complex_calculation(x: i32) -> i32 {
    let y = x * 2;
    y + 10
}

// Macros (compile-time code generation)
macro_rules! measure_time {
    ($block:expr) => {{
        use std::time::Instant;
        let start = Instant::now();
        let result = $block;
        let duration = start.elapsed();
        println!("Time: {:?}", duration);
        result
    }};
}

// Generic function with inline
#[inline]
fn process<T, F>(value: T, transform: F) -> T
where
    F: Fn(T) -> T,
{
    transform(value)
}

fn main() {
    // Using inline functions
    println!("Square: {}", square(5));
    println!("Add: {}", add(5, 3));
    println!("Complex: {}", complex_calculation(5));
    
    // Using macro
    let result = measure_time!({
        std::thread::sleep(std::time::Duration::from_millis(100));
        42
    });
    println!("Result: {}", result);
    
    // Generic inline
    let result = process(5, |x| x * 2);
    println!("Processed: {}", result);
}
Beginner
20. What are constants and statics in Rust?

const defines compile-time constants. static defines global variables that have a fixed memory location and can be mutable (static mut) but require unsafe access.

  • const: compile‑time, inlined, no fixed address
  • static: global, has fixed address, can be accessed anywhere
  • static mut: mutable global – requires unsafe to read/write
  • Lazy static: lazy_static! for runtime initialization
rust
// Higher-Order Functions in Rust
fn main() {
    // Function that takes a function as parameter
    fn apply_operation<F>(a: i32, b: i32, operation: F) -> i32
    where
        F: Fn(i32, i32) -> i32,
    {
        operation(a, b)
    }
    
    // Function that returns a function
    fn get_multiplier(factor: i32) -> impl Fn(i32) -> i32 {
        move |x| x * factor
    }
    
    // Function composition
    fn compose<A, B, C>(f: impl Fn(B) -> C, g: impl Fn(A) -> B) -> impl Fn(A) -> C {
        move |x| f(g(x))
    }
    
    // Higher-order function with multiple closures
    fn process<F, G>(value: i32, transform: F, filter: G) -> Option<i32>
    where
        F: Fn(i32) -> i32,
        G: Fn(i32) -> bool,
    {
        if filter(value) {
            Some(transform(value))
        } else {
            None
        }
    }
    
    // Usage with closures
    let result = apply_operation(10, 20, |a, b| a + b);
    println!("Result: {}", result);
    
    let double = get_multiplier(2);
    println!("Double: {}", double(5));
    
    let square = |x: i32| x * x;
    let add_ten = |x: i32| x + 10;
    let square_then_add_ten = compose(add_ten, square);
    println!("Square then add ten: {}", square_then_add_ten(5));
    
    let processed = process(5, |x| x * 2, |&x| x > 3);
    println!("Processed: {:?}", processed);
    
    // Using with named functions
    fn add(a: i32, b: i32) -> i32 {
        a + b
    }
    println!("Named: {}", apply_operation(10, 20, add));
    
    // Iterator higher-order functions
    let numbers = vec![1, 2, 3, 4, 5];
    let squared: Vec<i32> = numbers.iter().map(|&x| x * x).collect();
    let even: Vec<i32> = numbers.iter().filter(|&&x| x % 2 == 0).cloned().collect();
    let sum: i32 = numbers.iter().sum();
    
    println!("Squared: {:?}", squared);
    println!("Even: {:?}", even);
    println!("Sum: {}", sum);
}
Beginner
21. What are type aliases in Rust?

Type aliases (type) allow giving a new name to an existing type. They improve readability and reduce repetition, especially for complex types like Result<Vec<u8>, Error>.

  • Declaration: type Kilometers = i32;
  • Usage: let x: Kilometers = 5;
  • Generic: type MyResult<T> = Result<T, MyError>;
  • No new type: Only a synonym, not type-safe
rust
// Async/Await in Rust
use tokio::time::{sleep, Duration};

// Basic async function
async fn fetch_data() -> String {
    sleep(Duration::from_secs(1)).await;
    String::from("Data loaded")
}

// Async function with timeout
async fn fetch_with_timeout() -> Result<String, &'static str> {
    tokio::time::timeout(
        Duration::from_millis(500),
        fetch_data()
    ).await.map_err(|_| "Timed out")
}

// Multiple async tasks
async fn parallel_tasks() -> Vec<String> {
    let task1 = tokio::spawn(async {
        sleep(Duration::from_secs(1)).await;
        String::from("Task 1")
    });
    
    let task2 = tokio::spawn(async {
        sleep(Duration::from_millis(500)).await;
        String::from("Task 2")
    });
    
    let results = tokio::try_join!(task1, task2).unwrap();
    vec![results.0, results.1]
}

// Async with select!
async fn select_example() -> String {
    let data = tokio::spawn(async {
        sleep(Duration::from_millis(500)).await;
        String::from("Data ready")
    });
    
    let timeout = tokio::spawn(async {
        sleep(Duration::from_millis(1000)).await;
        String::from("Timeout")
    });
    
    tokio::select! {
        result = data => result.unwrap(),
        result = timeout => result.unwrap(),
    }
}

// Async stream (using tokio-stream)
use tokio_stream::StreamExt;

async fn stream_example() {
    let mut stream = tokio_stream::iter(0..10);
    while let Some(value) = stream.next().await {
        println!("Stream value: {}", value);
    }
}

#[tokio::main]
async fn main() {
    let data = fetch_data().await;
    println!("{}", data);
    
    match fetch_with_timeout().await {
        Ok(data) => println!("Data: {}", data),
        Err(e) => println!("Error: {}", e),
    }
    
    let results = parallel_tasks().await;
    println!("Results: {:?}", results);
    
    let result = select_example().await;
    println!("Select result: {}", result);
    
    stream_example().await;
}
Beginner
22. What is the newtype pattern in Rust?

Newtype is a wrapper around an existing type that creates a new distinct type. It provides type safety and allows adding custom methods or traits to the wrapped type.

  • Definition: struct Age(i32);
  • Access: use .0 to get inner value
  • Traits: can derive common traits like Debug
  • Benefits: Prevents mixing units (e.g., Age vs Weight)
rust
// Iterators and Streams in Rust
fn main() {
    // Basic iterator
    let numbers = vec![1, 2, 3, 4, 5];
    let doubled: Vec<i32> = numbers.iter().map(|&x| x * 2).collect();
    println!("Doubled: {:?}", doubled);
    
    // Iterator with filter
    let evens: Vec<i32> = numbers.iter().filter(|&&x| x % 2 == 0).cloned().collect();
    println!("Evens: {:?}", evens);
    
    // Iterator with reduce
    let sum: i32 = numbers.iter().sum();
    println!("Sum: {}", sum);
    
    // Custom iterator using generator-like pattern
    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 {
                self.current += 1;
                Some(self.current)
            } else {
                None
            }
        }
    }
    
    let counter = Counter { current: 0, max: 10 };
    let nums: Vec<u32> = counter.collect();
    println!("Counter: {:?}", nums);
    
    // Lazy iterators
    let lazy = (0..10)
        .map(|x| {
            println!("Mapping: {}", x);
            x * 2
        })
        .filter(|x| {
            println!("Filtering: {}", x);
            x % 3 == 0
        });
    
    let result: Vec<i32> = lazy.take(3).collect();
    println!("Result: {:?}", result);
    
    // Iterator adapters
    let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    let processed: Vec<i32> = numbers
        .iter()
        .skip(2)
        .take(5)
        .map(|&x| x * 2)
        .filter(|&x| x % 3 == 0)
        .collect();
    println!("Processed: {:?}", processed);
}
Beginner
23. What are Deref and Drop traits in Rust?

Deref allows customizing the dereference operator (*) and enables smart pointers to behave like references. Drop allows custom code to run when a value goes out of scope (like a destructor).

  • Deref: impl Deref for MyType { type Target = T; fn deref(&self) -> &T { ... } }
  • Drop: impl Drop for MyType { fn drop(&mut self) { ... } }
  • Deref coercion: auto conversion to the target type
  • Drop order: dropped in reverse order of declaration
rust
// Channels in Rust (MPSC)
use std::sync::mpsc;
use std::thread;
use std::time::Duration;

fn main() {
    // Basic channel
    let (tx, rx) = mpsc::channel();
    
    // Producer thread
    let tx1 = tx.clone();
    thread::spawn(move || {
        for i in 1..5 {
            tx1.send(i).unwrap();
            thread::sleep(Duration::from_millis(100));
        }
    });
    
    // Producer thread 2
    let tx2 = tx.clone();
    thread::spawn(move || {
        for i in 5..10 {
            tx2.send(i).unwrap();
            thread::sleep(Duration::from_millis(150));
        }
    });
    
    // Consumer
    for received in rx {
        println!("Received: {}", received);
    }
    
    // Async channel (tokio)
    #[tokio::main]
    async fn async_channel_example() {
        let (tx, mut rx) = tokio::sync::mpsc::channel(32);
        
        let tx_clone = tx.clone();
        tokio::spawn(async move {
            for i in 1..5 {
                tx_clone.send(i).await.unwrap();
                tokio::time::sleep(Duration::from_millis(100)).await;
            }
        });
        
        tokio::spawn(async move {
            for i in 5..10 {
                tx.send(i).await.unwrap();
                tokio::time::sleep(Duration::from_millis(150)).await;
            }
        });
        
        while let Some(value) = rx.recv().await {
            println!("Async received: {}", value);
        }
    }
    
    // Broadcast channel
    use tokio::sync::broadcast;
    
    #[tokio::main]
    async fn broadcast_example() {
        let (tx, mut rx1) = broadcast::channel(16);
        let mut rx2 = tx.subscribe();
        
        tokio::spawn(async move {
            let _ = tx.send(42);
        });
        
        tokio::spawn(async move {
            if let Ok(value) = rx1.recv().await {
                println!("Receiver 1: {}", value);
            }
        });
        
        tokio::spawn(async move {
            if let Ok(value) = rx2.recv().await {
                println!("Receiver 2: {}", value);
            }
        });
        
        tokio::time::sleep(Duration::from_millis(100)).await;
    }
}
Beginner
24. What is interior mutability with RefCell in Rust?

RefCell provides interior mutability – it allows mutable access even when the value is shared, by enforcing borrowing rules at runtime instead of compile time. It is single-threaded.

  • RefCell: let x = RefCell::new(5);
  • Borrow: let y = x.borrow(); (immutable)
  • Borrow mut: let mut y = x.borrow_mut();
  • Panic: if rules are violated at runtime (e.g., double borrow)
rust
// Enums and Pattern Matching in Rust
#[derive(Debug)]
enum Color {
    Red,
    Green,
    Blue,
}

#[derive(Debug)]
enum Status {
    Success(u32),
    Error(String),
    Loading,
}

// Enum with methods
impl Status {
    fn is_success(&self) -> bool {
        matches!(self, Status::Success(_))
    }
    
    fn get_code(&self) -> Option<u32> {
        match self {
            Status::Success(code) => Some(*code),
            _ => None,
        }
    }
}

// Discriminated union pattern
enum UiState {
    Success { data: String },
    Error { message: String },
    Loading,
    Idle,
}

impl UiState {
    fn is_loading(&self) -> bool {
        matches!(self, UiState::Loading)
    }
    
    fn data(&self) -> Option<&String> {
        match self {
            UiState::Success { data } => Some(data),
            _ => None,
        }
    }
}

fn main() {
    let color = Color::Red;
    let status = Status::Success(200);
    let state = UiState::Success {
        data: String::from("Data loaded"),
    };
    
    // Pattern matching
    match color {
        Color::Red => println!("Color is Red"),
        Color::Green => println!("Color is Green"),
        Color::Blue => println!("Color is Blue"),
    }
    
    match status {
        Status::Success(code) => println!("Success with code: {}", code),
        Status::Error(msg) => println!("Error: {}", msg),
        Status::Loading => println!("Loading..."),
    }
    
    // If let
    if let UiState::Success { data } = state {
        println!("Data: {}", data);
    }
    
    // While let
    let mut vec = vec![1, 2, 3];
    while let Some(value) = vec.pop() {
        println!("Popped: {}", value);
    }
    
    // Pattern matching with guards
    let number = 5;
    match number {
        n if n < 0 => println!("Negative"),
        n if n == 0 => println!("Zero"),
        n if n > 0 => println!("Positive"),
        _ => println!("Unknown"),
    }
}
Beginner
25. What are smart pointers Box and Rc in Rust?

Box<T> allocates memory on the heap and provides ownership. Rc<T> (reference counted) allows multiple owners by keeping a reference count. It is single‑threaded.

  • Box: let b = Box::new(5); – single owner, heap
  • Rc: let r = Rc::new(5); – shared ownership
  • Clone: let r2 = Rc::clone(&r); increments count
  • Weak: Rc::downgrade() to avoid cycles
rust
// Generics in Rust
// Generic struct
struct Box<T> {
    value: T,
}

impl<T> Box<T> {
    fn new(value: T) -> Self {
        Box { value }
    }
    
    fn get_value(&self) -> &T {
        &self.value
    }
}

// Generic function
fn swap<T>(first: T, second: T) -> (T, T) {
    (second, first)
}

// Generic with constraints
fn sum_numbers<T: std::ops::Add<Output = T> + Copy + From<u8>>(items: &[T]) -> T {
    let mut sum = T::from(0);
    for &item in items {
        sum = sum + item;
    }
    sum
}

// Generic with multiple constraints
trait Display {
    fn display(&self) -> String;
}

trait Countable {
    fn count(&self) -> usize;
}

fn process<T: Display + Countable>(item: &T) {
    println!("{}", item.display());
    println!("Count: {}", item.count());
}

// Variance - Covariant (using lifetimes)
struct Producer<'a, T> {
    value: &'a T,
}

// Contravariant
struct Consumer<T> {
    _phantom: std::marker::PhantomData<fn(T)>,
}

fn main() {
    // Generic struct
    let box_int = Box::new(42);
    let box_string = Box::new(String::from("Hello"));
    
    println!("Box int: {}", box_int.get_value());
    println!("Box string: {}", box_string.get_value());
    
    // Generic function
    let (a, b) = swap(1, 2);
    println!("Swapped: {}, {}", a, b);
    
    // Generic with constraints
    let numbers = vec![1, 2, 3, 4, 5];
    println!("Sum: {}", sum_numbers(&numbers));
    
    // Generic with multiple constraints
    struct MyData {
        value: String,
    }
    
    impl Display for MyData {
        fn display(&self) -> String {
            format!("Data: {}", self.value)
        }
    }
    
    impl Countable for MyData {
        fn count(&self) -> usize {
            self.value.len()
        }
    }
    
    let data = MyData { value: String::from("Hello") };
    process(&data);
}
Beginner
26. What is Arc and atomic reference counting in Rust?

Arc (Atomic Reference Counted) is a thread‑safe version of Rc. It uses atomic operations for reference counting, allowing shared ownership across threads.

  • Arc: let a = Arc::new(5);
  • Clone: let a2 = Arc::clone(&a);
  • Thread-safe: can be sent between threads
  • Weak: Arc::downgrade() to avoid cycles
rust
// Traits and Delegation in Rust
// Base trait
trait Repository {
    fn get_data(&self) -> String;
    fn save_data(&self, data: &str);
}

// Implementation
struct DatabaseRepository;

impl Repository for DatabaseRepository {
    fn get_data(&self) -> String {
        String::from("Data from database")
    }
    
    fn save_data(&self, data: &str) {
        println!("Saving to database: {}", data);
    }
}

// Delegation using composition
struct CachedRepository {
    delegate: Box<dyn Repository>,
    cache: Option<String>,
}

impl CachedRepository {
    fn new(delegate: Box<dyn Repository>) -> Self {
        CachedRepository {
            delegate,
            cache: None,
        }
    }
}

impl Repository for CachedRepository {
    fn get_data(&self) -> String {
        if let Some(cached) = &self.cache {
            return cached.clone();
        }
        let data = self.delegate.get_data();
        // Can't modify self in get_data, so we'd need interior mutability
        data
    }
    
    fn save_data(&self, data: &str) {
        self.delegate.save_data(data);
    }
}

// Better delegation with interior mutability
use std::cell::RefCell;

struct CachedRepositoryMutable {
    delegate: Box<dyn Repository>,
    cache: RefCell<Option<String>>,
}

impl CachedRepositoryMutable {
    fn new(delegate: Box<dyn Repository>) -> Self {
        CachedRepositoryMutable {
            delegate,
            cache: RefCell::new(None),
        }
    }
}

impl Repository for CachedRepositoryMutable {
    fn get_data(&self) -> String {
        if let Some(cached) = self.cache.borrow().as_ref() {
            return cached.clone();
        }
        let data = self.delegate.get_data();
        *self.cache.borrow_mut() = Some(data.clone());
        data
    }
    
    fn save_data(&self, data: &str) {
        self.delegate.save_data(data);
        *self.cache.borrow_mut() = None;
    }
}

// Lazy property pattern
struct LazyProperty<T> {
    value: RefCell<Option<T>>,
    init: Box<dyn Fn() -> T>,
}

impl<T> LazyProperty<T> {
    fn new<F: Fn() -> T + 'static>(init: F) -> Self {
        LazyProperty {
            value: RefCell::new(None),
            init: Box::new(init),
        }
    }
    
    fn get(&self) -> T
    where
        T: Clone,
    {
        if self.value.borrow().is_none() {
            let value = (self.init)();
            *self.value.borrow_mut() = Some(value.clone());
            value
        } else {
            self.value.borrow().as_ref().unwrap().clone()
        }
    }
}

fn main() {
    let db = DatabaseRepository;
    let cached = CachedRepositoryMutable::new(Box::new(db));
    
    println!("{}", cached.get_data());
    println!("{}", cached.get_data()); // Returns cached
    
    cached.save_data("New data");
    println!("{}", cached.get_data()); // Cache cleared
    
    // Lazy property
    let lazy = LazyProperty::new(|| {
        println!("Computing expensive data...");
        String::from("Expensive Result")
    });
    
    println!("{}", lazy.get());
    println!("{}", lazy.get()); // Cached
}
Beginner
27. What are Send and Sync traits in Rust?

Send indicates that ownership of a type can be transferred between threads. Sync indicates that a type can be shared between threads safely (i.e., &T is Send). These are marker traits that the compiler automatically implements for most types.

  • Send: allows moving values across threads
  • Sync: allows sharing references across threads
  • Rc: not Send or Sync
  • Arc: both Send and Sync
rust
// Singleton Pattern in Rust
use std::sync::{Arc, Mutex, OnceLock};

// Singleton using OnceLock
struct AppConfig {
    api_url: String,
    timeout: u32,
}

impl AppConfig {
    fn new() -> Self {
        AppConfig {
            api_url: String::from("https://api.example.com"),
            timeout: 5000,
        }
    }
    
    fn instance() -> &'static AppConfig {
        static INSTANCE: OnceLock<AppConfig> = OnceLock::new();
        INSTANCE.get_or_init(|| AppConfig::new())
    }
    
    fn print_config(&self) {
        println!("API URL: {}", self.api_url);
        println!("Timeout: {}", self.timeout);
    }
}

// Singleton with Mutex for mutable state
struct UserManager {
    users: Vec<String>,
}

impl UserManager {
    fn new() -> Self {
        UserManager {
            users: Vec::new(),
        }
    }
    
    fn instance() -> Arc<Mutex<Self>> {
        static INSTANCE: OnceLock<Arc<Mutex<UserManager>>> = OnceLock::new();
        INSTANCE
            .get_or_init(|| Arc::new(Mutex::new(UserManager::new())))
            .clone()
    }
    
    fn add_user(&mut self, name: &str) {
        self.users.push(name.to_string());
    }
    
    fn get_users(&self) -> Vec<String> {
        self.users.clone()
    }
}

// Singleton using lazy_static
use lazy_static::lazy_static;

lazy_static! {
    static ref DATABASE: Mutex<Database> = Mutex::new(Database::new());
}

struct Database {
    connected: bool,
}

impl Database {
    fn new() -> Self {
        Database { connected: true }
    }
    
    fn query(&self, sql: &str) -> String {
        format!("Executing: {}", sql)
    }
}

fn main() {
    // Using OnceLock singleton
    let config = AppConfig::instance();
    config.print_config();
    
    // Using Mutex singleton
    let manager = UserManager::instance();
    {
        let mut mgr = manager.lock().unwrap();
        mgr.add_user("Alice");
        mgr.add_user("Bob");
    }
    
    {
        let mgr = manager.lock().unwrap();
        println!("Users: {:?}", mgr.get_users());
    }
    
    // Using lazy_static singleton
    let db = DATABASE.lock().unwrap();
    println!("{}", db.query("SELECT * FROM users"));
}
Beginner
28. What is async/await basics in Rust?

async marks a function as asynchronous, returning a Future. await suspends execution until the future completes. Async is built on top of runtimes like Tokio.

  • async fn: async fn fetch() -> String { ... }
  • await: let data = fetch().await;
  • Runtimes: Tokio, async-std
  • main: #[tokio::main]
rust
// Builder Pattern and DSL in Rust
// Builder pattern
#[derive(Debug)]
struct User {
    name: String,
    age: u32,
    email: String,
    city: String,
}

struct UserBuilder {
    name: Option<String>,
    age: Option<u32>,
    email: Option<String>,
    city: Option<String>,
}

impl UserBuilder {
    fn new() -> Self {
        UserBuilder {
            name: None,
            age: None,
            email: None,
            city: None,
        }
    }
    
    fn name(mut self, name: &str) -> Self {
        self.name = Some(name.to_string());
        self
    }
    
    fn age(mut self, age: u32) -> Self {
        self.age = Some(age);
        self
    }
    
    fn email(mut self, email: &str) -> Self {
        self.email = Some(email.to_string());
        self
    }
    
    fn city(mut self, city: &str) -> Self {
        self.city = Some(city.to_string());
        self
    }
    
    fn build(self) -> Result<User, &'static str> {
        Ok(User {
            name: self.name.ok_or("Name is required")?,
            age: self.age.unwrap_or(0),
            email: self.email.unwrap_or_else(|| String::from("No email")),
            city: self.city.unwrap_or_else(|| String::from("Unknown")),
        })
    }
}

// Fluent interface
#[derive(Debug)]
struct Query {
    table: String,
    select: Vec<String>,
    conditions: Vec<String>,
    order: Vec<String>,
    limit: Option<usize>,
}

impl Query {
    fn new(table: &str) -> Self {
        Query {
            table: table.to_string(),
            select: Vec::new(),
            conditions: Vec::new(),
            order: Vec::new(),
            limit: None,
        }
    }
    
    fn select(mut self, fields: &[&str]) -> Self {
        self.select = fields.iter().map(|&s| s.to_string()).collect();
        self
    }
    
    fn where_condition(mut self, condition: &str) -> Self {
        self.conditions.push(condition.to_string());
        self
    }
    
    fn order_by(mut self, field: &str, desc: bool) -> Self {
        let direction = if desc { "DESC" } else { "ASC" };
        self.order.push(format!("{} {}", field, direction));
        self
    }
    
    fn limit(mut self, n: usize) -> Self {
        self.limit = Some(n);
        self
    }
    
    fn build(&self) -> String {
        let mut query = String::new();
        query.push_str("SELECT ");
        if self.select.is_empty() {
            query.push_str("*");
        } else {
            query.push_str(&self.select.join(", "));
        }
        query.push_str(&format!(" FROM {}", self.table));
        if !self.conditions.is_empty() {
            query.push_str(&format!(" WHERE {}", self.conditions.join(" AND ")));
        }
        if !self.order.is_empty() {
            query.push_str(&format!(" ORDER BY {}", self.order.join(", ")));
        }
        if let Some(limit) = self.limit {
            query.push_str(&format!(" LIMIT {}", limit));
        }
        query
    }
}

// DSL using macros
macro_rules! html {
    ($($tag:ident $(($($attr:tt)*))? { $($inner:tt)* })*) => {
        format!($(concat!("<", stringify!($tag), ">", html!(@inner $($inner)*), "</", stringify!($tag), ">")),*)
    };
    (@inner $($inner:tt)*) => {
        format!($(stringify!($inner)),*)
    };
}

fn main() {
    // Builder pattern
    let user = UserBuilder::new()
        .name("Alice")
        .age(25)
        .email("alice@example.com")
        .city("NYC")
        .build()
        .unwrap();
    
    println!("User: {:?}", user);
    
    // Query DSL
    let query = Query::new("users")
        .select(&["name", "age"])
        .where_condition("age > 18")
        .order_by("name", false)
        .limit(10)
        .build();
    
    println!("Query: {}", query);
    
    // HTML DSL example
    let html = format!("<h1>Hello</h1><p>World</p>");
    println!("HTML: {}", html);
}
Beginner
29. What are channels (mpsc) in Rust?

mpsc stands for multiple‑producer, single‑consumer. Channels provide a way to send messages between threads. The standard library provides std::sync::mpsc.

  • Sender/Receiver: let (tx, rx) = mpsc::channel();
  • Send: tx.send(value).unwrap();
  • Receive: let received = rx.recv().unwrap();
  • Multiple producers: clone the sender
rust
// Macros and Attributes in Rust
// Basic macro
macro_rules! hello {
    () => {
        println!("Hello, World!");
    };
    ($name:expr) => {
        println!("Hello, {}!", $name);
    };
    ($($name:expr),*) => {
        $(println!("Hello, {}!", $name);)*
    };
}

// Macro with repetition
macro_rules! vec_of_strings {
    ($($x:expr),*) => {
        vec![$($x.to_string()),*]
    };
}

// Macro with patterns
macro_rules! calculate {
    (add $a:expr, $b:expr) => {
        $a + $b
    };
    (sub $a:expr, $b:expr) => {
        $a - $b
    };
    (mul $a:expr, $b:expr) => {
        $a * $b
    };
    (div $a:expr, $b:expr) => {
        $a / $b
    };
}

// Attribute macro
#[derive(Debug, Clone, PartialEq)]
struct MyStruct {
    name: String,
    value: i32,
}

// Custom attribute (derive macro)
#[derive(Default)]
struct MyDefaultStruct {
    field1: String,
    field2: i32,
}

// Function attribute
#[inline]
fn fast_function(x: i32) -> i32 {
    x * 2
}

// Deprecated attribute
#[deprecated(since = "2.0", note = "Use new_function instead")]
fn old_function() {
    println!("Old function");
}

// Conditional compilation
#[cfg(target_os = "windows")]
fn platform_specific() {
    println!("Running on Windows");
}

#[cfg(target_os = "linux")]
fn platform_specific() {
    println!("Running on Linux");
}

fn main() {
    // Using macros
    hello!();
    hello!("Alice");
    hello!("Alice", "Bob", "Charlie");
    
    let strings = vec_of_strings!("hello", "world", "rust");
    println!("Strings: {:?}", strings);
    
    println!("Add: {}", calculate!(add 5, 3));
    println!("Mul: {}", calculate!(mul 5, 3));
    
    // Using attributes
    let my_struct = MyStruct {
        name: String::from("Test"),
        value: 42,
    };
    println!("{:?}", my_struct);
    
    let default_struct = MyDefaultStruct::default();
    println!("Default: {:?}", default_struct);
    
    old_function();
    platform_specific();
}
Beginner
30. How to test with assert macros in Rust?

Rust provides built‑in macros for testing: assert!, assert_eq!, and assert_ne!. Tests are functions marked with #[test] and run with cargo test.

  • Test function: #[test] fn test_add() { assert_eq!(add(2,2), 4); }
  • assert: panics if condition false
  • Should panic: #[should_panic]
  • Integration tests: in tests/ directory
rust
// Reflection and Type Information in Rust
use std::any::{Any, TypeId};

// Trait for type reflection
trait Reflect {
    fn type_name(&self) -> &'static str;
    fn type_id(&self) -> TypeId;
}

impl<T: 'static> Reflect for T {
    fn type_name(&self) -> &'static str {
        std::any::type_name::<T>()
    }
    
    fn type_id(&self) -> TypeId {
        TypeId::of::<T>()
    }
}

// Struct for reflection examples
#[derive(Debug)]
struct Person {
    name: String,
    age: u32,
}

impl Person {
    fn new(name: &str, age: u32) -> Self {
        Person {
            name: name.to_string(),
            age,
        }
    }
    
    fn greet(&self) -> String {
        format!("Hello, my name is {}", self.name)
    }
}

// Check type at runtime
fn check_type<T: 'static, U: 'static>() -> bool {
    TypeId::of::<T>() == TypeId::of::<U>()
}

// Downcasting
fn downcast_example() {
    let value: Box<dyn Any> = Box::new(42);
    
    if let Some(int_val) = value.downcast_ref::<i32>() {
        println!("Integer: {}", int_val);
    }
    
    let value2: Box<dyn Any> = Box::new(String::from("Hello"));
    
    if let Some(str_val) = value2.downcast_ref::<String>() {
        println!("String: {}", str_val);
    }
}

// Field reflection (using serde for serialization)
#[derive(serde::Serialize, serde::Deserialize, Debug)]
struct SerializedPerson {
    name: String,
    age: u32,
}

fn reflection_example() {
    let person = Person::new("Alice", 25);
    
    // Type name
    println!("Type name: {}", person.type_name());
    
    // Type ID
    println!("Type ID: {:?}", person.type_id());
    
    // Type checking
    println!("Is Person: {}", check_type::<Person, Person>());
    println!("Is String: {}", check_type::<Person, String>());
}

fn main() {
    reflection_example();
    downcast_example();
    
    // Serialization example
    let person = SerializedPerson {
        name: String::from("Alice"),
        age: 25,
    };
    
    let serialized = serde_json::to_string(&person).unwrap();
    println!("Serialized: {}", serialized);
    
    let deserialized: SerializedPerson = serde_json::from_str(&serialized).unwrap();
    println!("Deserialized: {:?}", deserialized);
}
Coding Round
31. Reverse a string

Reverse a string using chars().rev().collect() or manual iteration.

  • Built-in: s.chars().rev().collect()
  • Manual: Iterate from end to start
  • Using String: String::from_str(s).chars().rev().collect()
  • Complexity: O(n) time
rust
// Reverse a string in Rust
fn reverse_string(s: &str) -> String {
    s.chars().rev().collect()
}

fn main() {
    let s = "hello";
    let reversed = reverse_string(s);
    println!("Original: {}", s);
    println!("Reversed: {}", reversed);
}
Coding Round
32. Check palindrome

Check if a string is a palindrome using iterator methods or two-pointer approach.

  • Iterator: s.chars().eq(s.chars().rev())
  • Two-pointer: Compare from both ends
  • Case insensitive: to_lowercase()
  • Ignoring non-alphanumeric: filter(|c| c.is_alphanumeric())
rust
// Check palindrome in Rust
fn is_palindrome(s: &str) -> bool {
    let cleaned: String = s
        .chars()
        .filter(|c| c.is_alphanumeric())
        .map(|c| c.to_ascii_lowercase())
        .collect();
    cleaned == cleaned.chars().rev().collect::<String>()
}

fn is_palindrome_two_pointer(s: &str) -> bool {
    let chars: Vec<char> = s
        .chars()
        .filter(|c| c.is_alphanumeric())
        .map(|c| c.to_ascii_lowercase())
        .collect();
    
    let mut left = 0;
    let mut right = chars.len() - 1;
    
    while left < right {
        if chars[left] != chars[right] {
            return false;
        }
        left += 1;
        right -= 1;
    }
    true
}

fn main() {
    println!("racecar: {}", is_palindrome("racecar"));
    println!("hello: {}", is_palindrome("hello"));
    println!("A man a plan a canal Panama: {}", is_palindrome("A man a plan a canal Panama"));
}
Coding Round
33. Find max in array

Find maximum value using iter().max() or manual iteration.

  • Built-in: arr.iter().max()
  • Manual: Iterate and track max
  • Empty array: Returns None
  • Complexity: O(n) time
rust
// Find max in array in Rust
fn find_max(arr: &[i32]) -> Option<&i32> {
    arr.iter().max()
}

fn find_max_manual(arr: &[i32]) -> Option<i32> {
    if arr.is_empty() {
        return None;
    }
    let mut max_val = arr[0];
    for &num in arr {
        if num > max_val {
            max_val = num;
        }
    }
    Some(max_val)
}

fn main() {
    let numbers = vec![1, 5, 3, 9, 2];
    println!("Max: {:?}", find_max(&numbers));
    println!("Max manual: {:?}", find_max_manual(&numbers));
}
Coding Round
34. Remove duplicates

Remove duplicates using HashSet or manual tracking.

  • HashSet: set.into_iter().collect()
  • Manual: Track seen elements in vector
  • Preserve order: Use HashSet with filter
  • Complexity: O(n) time
rust
// Remove duplicates in Rust
fn remove_duplicates(arr: &[i32]) -> Vec<i32> {
    let mut result = Vec::new();
    for &item in arr {
        if !result.contains(&item) {
            result.push(item);
        }
    }
    result
}

fn remove_duplicates_set(arr: &[i32]) -> Vec<i32> {
    use std::collections::HashSet;
    let set: HashSet<i32> = arr.iter().cloned().collect();
    set.into_iter().collect()
}

fn main() {
    let numbers = vec![1, 2, 2, 3, 3, 4];
    println!("Original: {:?}", numbers);
    println!("Unique: {:?}", remove_duplicates(&numbers));
}
Coding Round
35. Merge arrays

Merge arrays using extend or concat.

  • extend: arr1.extend(arr2)
  • concat: arr1.concat(arr2)
  • Unique merge: Use HashSet
  • Complexity: O(n) time
rust
// Merge arrays in Rust
fn merge_arrays<T: Clone>(arr1: &[T], arr2: &[T]) -> Vec<T> {
    let mut result = arr1.to_vec();
    result.extend_from_slice(arr2);
    result
}

fn merge_unique<T: Clone + Eq + std::hash::Hash>(arr1: &[T], arr2: &[T]) -> Vec<T> {
    use std::collections::HashSet;
    let set: HashSet<_> = arr1.iter().chain(arr2.iter()).collect();
    set.into_iter().cloned().collect()
}

fn main() {
    let arr1 = vec![1, 2, 3];
    let arr2 = vec![3, 4, 5];
    println!("Merged: {:?}", merge_arrays(&arr1, &arr2));
    println!("Unique merged: {:?}", merge_unique(&arr1, &arr2));
}
Coding Round
36. Convert string to number

Convert string to number using parse().

  • parse: s.parse::<i32>()
  • Result type: Returns Result<T, ParseIntError>
  • Safe conversion: Use ok() or unwrap_or()
  • Error handling: Match on Result
rust
// Convert string to number in Rust
fn string_to_number(s: &str) -> Option<i32> {
    s.parse::<i32>().ok()
}

fn string_to_number_safe(s: &str) -> Result<i32, &'static str> {
    s.parse::<i32>().map_err(|_| "Invalid number")
}

fn main() {
    println!("42: {:?}", string_to_number("42"));
    println!("invalid: {:?}", string_to_number("invalid"));
    
    match string_to_number_safe("42") {
        Ok(num) => println!("Parsed: {}", num),
        Err(e) => println!("Error: {}", e),
    }
}
Coding Round
37. Loop through HashMap

Iterate through HashMap using for loop or iter().

  • for: for (key, value) in &map
  • iter: map.iter().for_each()
  • Keys: map.keys()
  • Values: map.values()
rust
// Loop through HashMap in Rust
use std::collections::HashMap;

fn main() {
    let mut map = HashMap::new();
    map.insert("name", "Alice");
    map.insert("age", "25");
    map.insert("city", "NYC");
    
    // Using for loop
    for (key, value) in &map {
        println!("{} => {}", key, value);
    }
    
    // Using iter
    map.iter().for_each(|(key, value)| {
        println!("{} => {}", key, value);
    });
    
    // Using keys
    for key in map.keys() {
        println!("Key: {}", key);
    }
    
    // Using values
    for value in map.values() {
        println!("Value: {}", value);
    }
}
Coding Round
38. Delay function execution

Delay execution using std::thread::sleep or tokio::time::sleep.

  • Thread sleep: thread::sleep(Duration::from_millis())
  • Async sleep: tokio::time::sleep(Duration::from_millis())
  • Blocking: Use std::thread
  • Non-blocking: Use async/await
rust
// Delay function execution in Rust
use std::thread;
use std::time::Duration;

fn delayed_execution(delay_ms: u64, f: impl Fn() + Send + 'static) {
    thread::spawn(move || {
        thread::sleep(Duration::from_millis(delay_ms));
        f();
    });
}

// Async delay
use tokio::time::sleep;

async fn async_delay(delay_ms: u64) {
    sleep(Duration::from_millis(delay_ms)).await;
}

#[tokio::main]
async fn main() {
    delayed_execution(2000, || {
        println!("After 2 seconds");
    });
    
    // Keep main alive
    thread::sleep(Duration::from_millis(2500));
    
    // Async delay
    async_delay(1000).await;
    println!("After 1 second (async)");
}
Coding Round
39. HTTP GET request

Make HTTP GET requests using reqwest library.

  • reqwest: reqwest::get(url).await
  • Synchronous: reqwest::blocking::get
  • Async: Use async/await
  • JSON parsing: .json::<T>()
rust
// HTTP GET request in Rust
use reqwest;

#[tokio::main]
async fn fetch_data(url: &str) -> Result<String, reqwest::Error> {
    let response = reqwest::get(url).await?;
    let body = response.text().await?;
    Ok(body)
}

async fn fetch_json<T: serde::de::DeserializeOwned>(url: &str) -> Result<T, reqwest::Error> {
    let response = reqwest::get(url).await?;
    let data = response.json::<T>().await?;
    Ok(data)
}

#[derive(serde::Deserialize, Debug)]
struct User {
    id: u32,
    name: String,
    email: String,
}

#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
    let data = fetch_data("https://jsonplaceholder.typicode.com/users/1").await?;
    println!("Data: {}", data);
    
    let user: User = fetch_json("https://jsonplaceholder.typicode.com/users/1").await?;
    println!("User: {:?}", user);
    
    Ok(())
}
Coding Round
40. Create a promise-like Future

Create a Future using async functions or custom implementations.

  • async fn: async fn fetch() -> String
  • Custom Future: Implement Future trait
  • Ready future: futures::future::ready()
  • Poll: Override poll method
rust
// Future (Promise-like) in Rust
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::time::Duration;
use tokio::time::sleep;

// Async function (returns a Future)
async fn fetch_data() -> String {
    // Simulate async operation
    sleep(Duration::from_millis(100)).await;
    String::from("Data fetched!")
}

// Custom Future implementation
struct MyFuture {
    completed: bool,
    value: Option<String>,
}

impl MyFuture {
    fn new() -> Self {
        MyFuture {
            completed: false,
            value: None,
        }
    }
}

impl Future for MyFuture {
    type Output = String;

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        if self.completed {
            Poll::Ready(self.value.take().unwrap_or_default())
        } else {
            // Simulate some work
            self.completed = true;
            self.value = Some(String::from("Custom future result"));
            Poll::Ready(self.value.take().unwrap())
        }
    }
}

// Using ready future from futures crate
use futures::future::ready;

// Combine multiple futures
async fn combine_futures() -> String {
    let future1 = fetch_data();
    let future2 = fetch_data();
    
    let (result1, result2) = tokio::join!(future1, future2);
    format!("{} {}", result1, result2)
}

#[tokio::main]
async fn main() {
    // Using async function
    let result = fetch_data().await;
    println!("Async result: {}", result);
    
    // Using custom future
    let custom = MyFuture::new().await;
    println!("Custom future: {}", custom);
    
    // Using ready future
    let ready_result = ready(String::from("Ready future")).await;
    println!("Ready future: {}", ready_result);
    
    // Combining futures
    let combined = combine_futures().await;
    println!("Combined: {}", combined);
}
Coding Round
41. Factorial

Calculate factorial using recursion or iteration with product().

  • Recursive: n * factorial(n-1)
  • Iterative: (1..=n).product()
  • Base case: n <= 1
  • Edge cases: 0! = 1
rust
// Factorial in Rust
use std::io;

// Recursive factorial
fn factorial_recursive(n: u64) -> u64 {
    if n <= 1 {
        1
    } else {
        n * factorial_recursive(n - 1)
    }
}

// Iterative factorial using product()
fn factorial_iterative(n: u64) -> u64 {
    (1..=n).product()
}

// Iterative factorial using loop
fn factorial_loop(n: u64) -> u64 {
    let mut result = 1;
    for i in 1..=n {
        result *= i;
    }
    result
}

// Factorial with error handling for large numbers
fn factorial_safe(n: u64) -> Option<u64> {
    let mut result = 1u64;
    for i in 1..=n {
        result = result.checked_mul(i)?;
    }
    Some(result)
}

fn main() {
    let n = 5;
    
    println!("Factorial of {}:", n);
    println!("Recursive: {}", factorial_recursive(n));
    println!("Iterative (product): {}", factorial_iterative(n));
    println!("Iterative (loop): {}", factorial_loop(n));
    
    // Safe version
    match factorial_safe(20) {
        Some(result) => println!("Safe factorial: {}", result),
        None => println!("Overflow!"),
    }
    
    // Input from user
    println!("Enter a number: ");
    let mut input = String::new();
    io::stdin().read_line(&mut input).unwrap();
    let num: u64 = input.trim().parse().unwrap();
    println!("Factorial: {}", factorial_recursive(num));
}
Coding Round
42. Fibonacci

Calculate Fibonacci using recursion, iteration, or memoization.

  • Recursive: fib(n-1) + fib(n-2)
  • Iterative: Loop with variables
  • Memoization: Cache results in HashMap
  • Complexity: O(n) with memoization
rust
// Fibonacci in Rust
fn fibonacci(n: u64) -> u64 {
    if n <= 1 {
        n
    } else {
        fibonacci(n - 1) + fibonacci(n - 2)
    }
}

fn fibonacci_iterative(n: u64) -> u64 {
    let mut a = 0;
    let mut b = 1;
    for _ in 0..n {
        let temp = a + b;
        a = b;
        b = temp;
    }
    a
}

fn main() {
    println!("fib(8) = {}", fibonacci(8));
    println!("fib(8) iterative = {}", fibonacci_iterative(8));
}
Coding Round
43. FizzBuzz

FizzBuzz using if-else or match statement.

  • Modulo: i % 15 == 0
  • Order: Check 15 first
  • Range: for i in 1..=n
  • Return vector: Collect results
rust
// FizzBuzz in Rust
fn fizzbuzz(n: u32) -> Vec<String> {
    (1..=n)
        .map(|i| {
            if i % 15 == 0 {
                "FizzBuzz".to_string()
            } else if i % 3 == 0 {
                "Fizz".to_string()
            } else if i % 5 == 0 {
                "Buzz".to_string()
            } else {
                i.to_string()
            }
        })
        .collect()
}

fn main() {
    let result = fizzbuzz(15);
    for (i, item) in result.iter().enumerate() {
        println!("{}: {}", i + 1, item);
    }
}
Coding Round
44. Find missing number

Find missing number using formula or XOR method.

  • Formula: total - sum
  • XOR: XOR all numbers and indices
  • Complexity: O(n) time
  • Edge cases: Empty array, missing first or last
rust
// Find missing number in Rust
fn find_missing(arr: &[i32]) -> i32 {
    let n = arr.len() + 1;
    let total = n * (n + 1) / 2;
    let sum: i32 = arr.iter().sum();
    (total - sum) as i32
}

fn find_missing_xor(arr: &[i32]) -> i32 {
    let n = arr.len() + 1;
    let mut xor_sum = 0;
    for i in 1..=n {
        xor_sum ^= i as i32;
    }
    for &num in arr {
        xor_sum ^= num;
    }
    xor_sum
}

fn main() {
    let numbers = vec![1, 2, 4, 5, 6];
    println!("Missing: {}", find_missing(&numbers));
    println!("Missing (XOR): {}", find_missing_xor(&numbers));
}
Coding Round
45. Find duplicates

Find duplicates using HashSet or manual tracking.

  • HashSet: Track seen elements
  • Filter: arr.iter().filter(|&x| seen.contains(x))
  • Complexity: O(n) time
  • Returns: Vector of duplicates
rust
// Find duplicates in Rust
use std::collections::HashSet;

fn find_duplicates(arr: &[i32]) -> Vec<i32> {
    let mut seen = HashSet::new();
    let mut duplicates = HashSet::new();
    for &item in arr {
        if seen.contains(&item) {
            duplicates.insert(item);
        } else {
            seen.insert(item);
        }
    }
    duplicates.into_iter().collect()
}

fn main() {
    let numbers = vec![1, 2, 3, 2, 4, 3];
    println!("Duplicates: {:?}", find_duplicates(&numbers));
}
Coding Round
46. Sum of array

Calculate sum using iter().sum() or manual iteration.

  • Built-in: arr.iter().sum()
  • Manual: Iterate and accumulate
  • Fold: arr.iter().fold(0, |acc, x| acc + x)
  • Complexity: O(n) time
rust
// Sum of array in Rust
fn sum_array(arr: &[i32]) -> i32 {
    arr.iter().sum()
}

fn sum_array_manual(arr: &[i32]) -> i32 {
    let mut total = 0;
    for &num in arr {
        total += num;
    }
    total
}

fn main() {
    let numbers = vec![1, 2, 3, 4, 5];
    println!("Sum: {}", sum_array(&numbers));
    println!("Sum manual: {}", sum_array_manual(&numbers));
}
Coding Round
47. Average of array

Calculate average using sum divided by length.

  • Method: sum / len as f64
  • Empty array: Returns None
  • Precision: Returns f64
  • Edge case: Handle empty array
rust
// Average of array in Rust
fn average_array(arr: &[f64]) -> Option<f64> {
    if arr.is_empty() {
        return None;
    }
    let sum: f64 = arr.iter().sum();
    Some(sum / arr.len() as f64)
}

fn main() {
    let numbers = vec![1.0, 2.0, 3.0, 4.0, 5.0];
    println!("Average: {:?}", average_array(&numbers));
}
Coding Round
48. Sort array ascending

Sort using sort() or sort_unstable().

  • sort(): arr.sort()
  • sort_unstable(): Faster but not stable
  • Complexity: O(n log n)
  • In-place: Modifies original array
rust
// Sort array ascending in Rust
fn sort_ascending(arr: &[i32]) -> Vec<i32> {
    let mut sorted = arr.to_vec();
    sorted.sort();
    sorted
}

fn main() {
    let numbers = vec![5, 2, 8, 1, 9];
    println!("Sorted: {:?}", sort_ascending(&numbers));
}
Coding Round
49. Sort array descending

Sort descending using sort_by or sort_unstable_by.

  • sort_by: arr.sort_by(|a, b| b.cmp(a))
  • Reverse: arr.sort(); arr.reverse()
  • Complexity: O(n log n)
  • In-place: Modifies original array
rust
// Sort array descending in Rust
fn sort_descending(arr: &[i32]) -> Vec<i32> {
    let mut sorted = arr.to_vec();
    sorted.sort_by(|a, b| b.cmp(a));
    sorted
}

fn main() {
    let numbers = vec![5, 2, 8, 1, 9];
    println!("Sorted descending: {:?}", sort_descending(&numbers));
}
Coding Round
50. Flatten nested array

Flatten nested arrays using flat_map or recursion.

  • flat_map: arr.iter().flat_map(|v| v.clone())
  • concat: arr.concat()
  • Recursive: Check if element is array
  • Complexity: O(n) time
rust
// Flatten nested array in Rust
fn flatten_array<T: Clone>(arr: &[Vec<T>]) -> Vec<T> {
    arr.iter().flat_map(|v| v.clone()).collect()
}

fn flatten_nested<T: Clone>(arr: &[impl Clone + IntoIterator<Item = T>]) -> Vec<T> {
    arr.iter().flat_map(|v| v.clone()).collect()
}

fn main() {
    let nested = vec![vec![1, 2], vec![3, 4], vec![5, 6]];
    println!("Flattened: {:?}", flatten_array(&nested));
}
Coding Round
51. Chunk array

Split array into chunks using chunks() method.

  • chunks: arr.chunks(size).map(|c| c.to_vec()).collect()
  • Manual: Iterate with step size
  • Edge case: Handle last chunk
  • Complexity: O(n) time
rust
// Chunk array in Rust
fn chunk_array<T: Clone>(arr: &[T], size: usize) -> Vec<Vec<T>> {
    arr.chunks(size).map(|chunk| chunk.to_vec()).collect()
}

fn main() {
    let numbers = vec![1, 2, 3, 4, 5, 6];
    println!("Chunks: {:?}", chunk_array(&numbers, 2));
}
Coding Round
53. Quick sort

Quick sort using recursion and partitioning.

  • Algorithm: Choose pivot, partition, recurse
  • Time: O(n log n) average
  • In-place: Implement for performance
  • Pivot: First element or random
rust
// Quick sort in Rust
fn quick_sort<T: Ord + Clone>(arr: &[T]) -> Vec<T> {
    if arr.len() <= 1 {
        return arr.to_vec();
    }
    
    let pivot = &arr[0];
    let left: Vec<T> = arr.iter().filter(|&x| x < pivot).cloned().collect();
    let right: Vec<T> = arr.iter().filter(|&x| x > pivot).cloned().collect();
    let mut result = quick_sort(&left);
    result.push(pivot.clone());
    result.extend(quick_sort(&right));
    result
}

fn main() {
    let numbers = vec![5, 3, 8, 4, 2, 7, 1, 6];
    println!("Sorted: {:?}", quick_sort(&numbers));
}
Coding Round
54. Merge sort

Merge sort using divide-and-conquer and merging.

  • Algorithm: Divide, sort, merge
  • Time: O(n log n)
  • Stable: Maintains relative order
  • Space: O(n) auxiliary space
rust
// Merge sort in Rust
fn merge_sort<T: Ord + Clone>(arr: &[T]) -> Vec<T> {
    if arr.len() <= 1 {
        return arr.to_vec();
    }
    
    let mid = arr.len() / 2;
    let left = merge_sort(&arr[..mid]);
    let right = merge_sort(&arr[mid..]);
    merge(&left, &right)
}

fn merge<T: Ord + Clone>(left: &[T], right: &[T]) -> Vec<T> {
    let mut result = Vec::with_capacity(left.len() + right.len());
    let mut i = 0;
    let mut j = 0;
    
    while i < left.len() && j < right.len() {
        if left[i] <= right[j] {
            result.push(left[i].clone());
            i += 1;
        } else {
            result.push(right[j].clone());
            j += 1;
        }
    }
    
    result.extend_from_slice(&left[i..]);
    result.extend_from_slice(&right[j..]);
    result
}

fn main() {
    let numbers = vec![5, 3, 8, 4, 2, 7, 1, 6];
    println!("Sorted: {:?}", merge_sort(&numbers));
}
Coding Round
55. Bubble sort

Bubble sort with early termination optimization.

  • Algorithm: Compare adjacent, swap
  • Time: O(n²) worst case
  • Optimization: Stop if no swaps
  • In-place: Modifies original array
rust
// Bubble sort in Rust
fn bubble_sort<T: Ord>(arr: &mut [T]) {
    let len = arr.len();
    for i in 0..len {
        let mut swapped = false;
        for j in 0..len - i - 1 {
            if arr[j] > arr[j + 1] {
                arr.swap(j, j + 1);
                swapped = true;
            }
        }
        if !swapped {
            break;
        }
    }
}

fn main() {
    let mut numbers = vec![5, 3, 8, 4, 2, 7, 1, 6];
    bubble_sort(&mut numbers);
    println!("Sorted: {:?}", numbers);
}
Coding Round
56. Intersection of arrays

Find common elements using HashSet or iterator methods.

  • HashSet: set1.intersection(&set2).collect()
  • Filter: arr1.iter().filter(|x| arr2.contains(x))
  • Complexity: O(n) time with HashSet
  • Return: Vector of common elements
rust
// Intersection of arrays in Rust
use std::collections::HashSet;

fn intersection<T: Eq + std::hash::Hash + Clone>(arr1: &[T], arr2: &[T]) -> Vec<T> {
    let set1: HashSet<_> = arr1.iter().cloned().collect();
    let set2: HashSet<_> = arr2.iter().cloned().collect();
    set1.intersection(&set2).cloned().collect()
}

fn main() {
    let arr1 = vec![1, 2, 3, 4];
    let arr2 = vec![3, 4, 5, 6];
    println!("Intersection: {:?}", intersection(&arr1, &arr2));
}
Coding Round
57. Union of arrays

Combine arrays with unique elements using HashSet.

  • HashSet: set1.union(&set2).collect()
  • Extend: set1.extend(set2)
  • Complexity: O(n) time
  • Return: Vector of unique elements
rust
// Union of arrays in Rust
use std::collections::HashSet;

fn union<T: Eq + std::hash::Hash + Clone>(arr1: &[T], arr2: &[T]) -> Vec<T> {
    let set1: HashSet<_> = arr1.iter().cloned().collect();
    let set2: HashSet<_> = arr2.iter().cloned().collect();
    set1.union(&set2).cloned().collect()
}

fn main() {
    let arr1 = vec![1, 2, 3];
    let arr2 = vec![3, 4, 5];
    println!("Union: {:?}", union(&arr1, &arr2));
}
Coding Round
58. Difference of arrays

Find elements in first array not in second using HashSet.

  • HashSet: set1.difference(&set2).collect()
  • Symmetric difference: set1.symmetric_difference(&set2).collect()
  • Complexity: O(n) time
  • Return: Vector of differences
rust
// Difference of arrays in Rust
use std::collections::HashSet;

fn difference<T: Eq + std::hash::Hash + Clone>(arr1: &[T], arr2: &[T]) -> Vec<T> {
    let set1: HashSet<_> = arr1.iter().cloned().collect();
    let set2: HashSet<_> = arr2.iter().cloned().collect();
    set1.difference(&set2).cloned().collect()
}

fn symmetric_difference<T: Eq + std::hash::Hash + Clone>(arr1: &[T], arr2: &[T]) -> Vec<T> {
    let set1: HashSet<_> = arr1.iter().cloned().collect();
    let set2: HashSet<_> = arr2.iter().cloned().collect();
    set1.symmetric_difference(&set2).cloned().collect()
}

fn main() {
    let arr1 = vec![1, 2, 3, 4];
    let arr2 = vec![3, 4, 5, 6];
    println!("Difference: {:?}", difference(&arr1, &arr2));
    println!("Symmetric difference: {:?}", symmetric_difference(&arr1, &arr2));
}
Coding Round
59. Group by property

Group objects by property using HashMap.

  • HashMap: groups.entry(key).or_insert(Vec::new()).push(item)
  • Iterate: For each item, group by key
  • Complexity: O(n) time
  • Return: HashMap with grouped items
rust
// Group by property in Rust
use std::collections::HashMap;

#[derive(Debug, Clone)]
struct Item {
    type_: String,
    name: String,
}

fn group_by_property(items: &[Item], key: &str) -> HashMap<String, Vec<Item>> {
    let mut groups = HashMap::new();
    for item in items {
        let key_value = match key {
            "type" => item.type_.clone(),
            _ => item.name.clone(),
        };
        groups.entry(key_value).or_insert_with(Vec::new).push(item.clone());
    }
    groups
}

fn main() {
    let items = vec![
        Item { type_: "fruit".to_string(), name: "apple".to_string() },
        Item { type_: "fruit".to_string(), name: "banana".to_string() },
        Item { type_: "veg".to_string(), name: "carrot".to_string() },
    ];
    
    let groups = group_by_property(&items, "type");
    for (key, items) in &groups {
        println!("{}: {:?}", key, items);
    }
}
Coding Round
60. Deep clone object

Deep clone using Clone trait or manual implementation.

  • Clone: obj.clone() (for Clone types)
  • Manual: Recursively copy nested structures
  • serde: Serialize and deserialize
  • Benefits: Complete independent copy
rust
// Deep clone in Rust
#[derive(Debug, Clone)]
struct Address {
    city: String,
    zip: String,
}

#[derive(Debug, Clone)]
struct User {
    name: String,
    address: Address,
}

fn deep_clone<T: Clone>(obj: &T) -> T {
    obj.clone()
}

fn main() {
    let original = User {
        name: "Alice".to_string(),
        address: Address {
            city: "NYC".to_string(),
            zip: "10001".to_string(),
        },
    };
    
    let cloned = deep_clone(&original);
    // Since we have a clone, we can modify the clone
    // In Rust, clone creates a deep copy by default for structs with Clone
    
    // This would require mutability
    // cloned.name = "Bob".to_string();
    // cloned.address.city = "LA".to_string();
    
    println!("Original: {:?}", original);
    println!("Cloned: {:?}", cloned);
}
Coding Round
61. Immutable update

Perform immutable updates using struct update syntax or serde_json.

  • Struct update: User { age: 26, ..state.user }
  • Clone: Clone and modify
  • serde_json: JSON manipulation
  • Return: New immutable object
rust
// Immutable Updates in Rust
use serde_json::json;

#[derive(Debug, Clone)]
struct User {
    id: u32,
    name: String,
    age: u32,
    email: String,
}

impl User {
    fn new(id: u32, name: &str, age: u32, email: &str) -> Self {
        User {
            id,
            name: name.to_string(),
            age,
            email: email.to_string(),
        }
    }
}

fn main() {
    let user = User::new(1, "Alice", 25, "alice@example.com");
    println!("Original: {:?}", user);
    
    // Method 1: Struct update syntax (immutable)
    let updated_user = User {
        age: 26,
        email: "alice@new.com".to_string(),
        ..user
    };
    println!("Updated (struct update): {:?}", updated_user);
    
    // Method 2: Clone and modify
    let mut cloned_user = user.clone();
    cloned_user.age = 27;
    cloned_user.name = "Alice Smith".to_string();
    println!("Updated (clone): {:?}", cloned_user);
    
    // Method 3: Functional update using helper function
    fn update_user_age(user: &User, new_age: u32) -> User {
        User {
            age: new_age,
            ..user.clone()
        }
    }
    let updated_via_fn = update_user_age(&user, 28);
    println!("Updated (function): {:?}", updated_via_fn);
    
    // Method 4: Using serde_json for JSON manipulation
    let json_user = json!({
        "id": user.id,
        "name": user.name,
        "age": user.age,
        "email": user.email
    });
    println!("JSON user: {}", json_user);
    
    // Modify JSON immutably
    let updated_json = json_user.as_object().map(|obj| {
        let mut new_obj = obj.clone();
        new_obj.insert("age".to_string(), json!(26));
        new_obj.insert("email".to_string(), json!("alice@new.com"));
        new_obj
    });
    println!("Updated JSON: {:?}", updated_json);
}
Coding Round
62. Pipe function

Pipe composes functions from left to right using closures.

  • Implementation: |x| f2(f1(x))
  • Chaining: Chain multiple functions
  • Return: Composed function
  • Direction: Left to right
rust
// Pipe function in Rust
fn pipe<T, F1, F2>(f1: F1, f2: F2) -> impl Fn(T) -> T
where
    F1: Fn(T) -> T,
    F2: Fn(T) -> T,
{
    move |x| f2(f1(x))
}

fn compose<T, F1, F2>(f1: F1, f2: F2) -> impl Fn(T) -> T
where
    F1: Fn(T) -> T,
    F2: Fn(T) -> T,
{
    move |x| f1(f2(x))
}

fn main() {
    let double = |x: i32| x * 2;
    let add_ten = |x: i32| x + 10;
    let square = |x: i32| x * x;
    
    let process = pipe(double, add_ten);
    let process_composed = compose(add_ten, square);
    
    println!("Pipe: {}", process(5));
    println!("Composed: {}", process_composed(5));
}
Coding Round
63. Compose function

Compose functions from right to left using closures.

  • Implementation: |x| f1(f2(x))
  • Chaining: Chain multiple functions
  • Return: Composed function
  • Direction: Right to left
rust
// Compose function in Rust
fn compose<T, F, G>(f: F, g: G) -> impl Fn(T) -> T
where
    F: Fn(T) -> T,
    G: Fn(T) -> T,
{
    move |x| f(g(x))
}

fn main() {
    let double = |x: i32| x * 2;
    let add_ten = |x: i32| x + 10;
    let square = |x: i32| x * x;
    
    let square_then_add_ten = compose(add_ten, square);
    let double_then_square = compose(square, double);
    
    println!("Square then add ten: {}", square_then_add_ten(5));
    println!("Double then square: {}", double_then_square(5));
}
Coding Round
64. Memoization

Cache function results based on arguments using HashMap.

  • Cache: HashMap<T, U>
  • Key: Function arguments
  • Return: Cached or computed result
  • Trade-off: Memory for speed
rust
// Memoization in Rust
use std::collections::HashMap;

fn memoize<F, T, U>(mut f: F) -> impl FnMut(T) -> U
where
    F: FnMut(T) -> U,
    T: Eq + std::hash::Hash + Clone,
    U: Clone,
{
    let mut cache = HashMap::new();
    move |arg| {
        if let Some(result) = cache.get(&arg) {
            return result.clone();
        }
        let result = f(arg.clone());
        cache.insert(arg, result.clone());
        result
    }
}

// Fibonacci with memoization
fn fib_memo() -> impl FnMut(u64) -> u64 {
    let mut cache = HashMap::new();
    move |n| {
        if n <= 1 {
            return n;
        }
        if let Some(&result) = cache.get(&n) {
            return result;
        }
        let result = fib_memo()(n - 1) + fib_memo()(n - 2);
        cache.insert(n, result);
        result
    }
}

fn main() {
    let mut fib = memoize(|n: u64| {
        if n <= 1 {
            n
        } else {
            fib(n - 1) + fib(n - 2)
        }
    });
    
    println!("Fib(10) = {}", fib(10));
}
Coding Round
65. Once function

Ensure a function is called only once using RefCell and flags.

  • Closure: let called = RefCell::new(false)
  • Result: Cache the result
  • Return: Function with guard
  • Use case: Initialization
rust
// Once function in Rust
fn once<F, T>(f: F) -> impl Fn() -> T
where
    F: Fn() -> T,
    T: Clone,
{
    use std::cell::RefCell;
    let called = RefCell::new(false);
    let result = RefCell::new(None);
    
    move || {
        if !*called.borrow() {
            *called.borrow_mut() = true;
            *result.borrow_mut() = Some(f());
        }
        result.borrow().as_ref().unwrap().clone()
    }
}

fn main() {
    let initialize = once(|| {
        println!("Initialized");
        42
    });
    
    println!("First call: {}", initialize());
    println!("Second call: {}", initialize());
}
Coding Round
66. Debounce with leading edge

Debounce with leading edge using timers and timestamp tracking.

  • Timer: thread::sleep or tokio::time::sleep
  • Leading edge: Execute immediately
  • Cooldown: Wait before next execution
  • Use case: Search input, API calls
rust
// Debounce with leading edge in Rust
use std::time::{Duration, Instant};
use std::thread;

fn debounce_leading<T, F>(delay: Duration, mut f: F) -> impl FnMut() -> T
where
    F: FnMut() -> T,
    T: Clone,
{
    let mut last_call = Instant::now() - delay;
    let mut timer = None;
    let mut result = None;
    
    move || {
        let now = Instant::now();
        if now - last_call < delay {
            if timer.is_none() {
                let last = last_call;
                timer = Some(thread::spawn(move || {
                    thread::sleep(delay - (now - last));
                    // In a real implementation, we'd need to handle this differently
                }));
            }
            result.clone().unwrap()
        } else {
            last_call = now;
            result = Some(f());
            result.clone().unwrap()
        }
    }
}

fn main() {
    let mut debounced = debounce_leading(Duration::from_millis(1000), || {
        println!("Executed");
        42
    });
    
    debounced();
    debounced();
}
Coding Round
67. Throttle with leading edge

Throttle with leading edge using timestamp tracking.

  • Timestamp: Track last execution time
  • Leading edge: Execute if enough time passed
  • Rate limiting: At most once per period
  • Use case: Scroll events, resize
rust
// Throttle with leading edge in Rust
use std::time::{Duration, Instant};

fn throttle_leading<T, F>(delay: Duration, mut f: F) -> impl FnMut() -> T
where
    F: FnMut() -> T,
    T: Clone,
{
    let mut last_call = Instant::now() - delay;
    
    move || {
        let now = Instant::now();
        if now - last_call >= delay {
            last_call = now;
            f()
        } else {
            // Return a default or last value
            // In practice, you'd want to return the last result
            panic!("Throttled call");
        }
    }
}

fn main() {
    let mut throttled = throttle_leading(Duration::from_millis(1000), || {
        println!("Executed");
        42
    });
    
    throttled();
    throttled(); // This will be throttled
}
Coding Round
68. Deep equal

Deep equality comparison using PartialEq trait.

  • PartialEq: #[derive(PartialEq)]
  • Manual: Recursive comparison
  • Arrays: Compare elements recursively
  • Objects: Compare fields recursively
rust
// Deep equal in Rust
#[derive(Debug, PartialEq)]
struct Address {
    city: String,
    zip: String,
}

#[derive(Debug, PartialEq)]
struct User {
    name: String,
    address: Address,
}

fn deep_equal<T: PartialEq>(a: &T, b: &T) -> bool {
    a == b
}

fn main() {
    let user1 = User {
        name: "Alice".to_string(),
        address: Address {
            city: "NYC".to_string(),
            zip: "10001".to_string(),
        },
    };
    
    let user2 = User {
        name: "Alice".to_string(),
        address: Address {
            city: "NYC".to_string(),
            zip: "10001".to_string(),
        },
    };
    
    let user3 = User {
        name: "Bob".to_string(),
        address: Address {
            city: "LA".to_string(),
            zip: "90001".to_string(),
        },
    };
    
    println!("User1 == User2: {}", deep_equal(&user1, &user2));
    println!("User1 == User3: {}", deep_equal(&user1, &user3));
}
Coding Round
69. Observable pattern

Observable pattern with subscribers and notifications using Arc<Mutex>.

  • Observable: Maintains subscribers
  • Subscribe: Add callback
  • Notify: Call all subscribers
  • Unsubscribe: Remove callback
rust
// Observable pattern in Rust
use std::sync::{Arc, Mutex};
use std::thread;

#[derive(Clone)]
struct Observable<T: Clone + Send + 'static> {
    subscribers: Arc<Mutex<Vec<Box<dyn Fn(T) + Send>>>>,
}

impl<T: Clone + Send + 'static> Observable<T> {
    fn new() -> Self {
        Observable {
            subscribers: Arc::new(Mutex::new(Vec::new())),
        }
    }
    
    fn subscribe<F>(&self, callback: F) -> impl Fn()
    where
        F: Fn(T) + Send + 'static,
    {
        let mut subscribers = self.subscribers.lock().unwrap();
        subscribers.push(Box::new(callback) as Box<dyn Fn(T) + Send>);
        let subscribers = self.subscribers.clone();
        
        move || {
            let mut subs = subscribers.lock().unwrap();
            // In practice, we'd need to remove the specific callback
            // This is a simplified version
        }
    }
    
    fn notify(&self, data: T) {
        let subscribers = self.subscribers.lock().unwrap();
        for subscriber in subscribers.iter() {
            subscriber(data.clone());
        }
    }
}

fn main() {
    let observable = Observable::new();
    
    let _unsubscribe = observable.subscribe(|data| {
        println!("Observer 1 received: {}", data);
    });
    
    observable.subscribe(|data| {
        println!("Observer 2 received: {}", data);
    });
    
    observable.notify("Hello World".to_string());
}
Coding Round
70. Singleton pattern

Singleton pattern using OnceLock or lazy_static.

  • OnceLock: static INSTANCE: OnceLock<T> = OnceLock::new()
  • lazy_static: lazy_static! { static ref INSTANCE: T = T::new() }
  • Thread-safe: Arc and Mutex for mutable state
  • Global access: Through static reference
rust
// Singleton pattern in Rust
use std::sync::{Arc, Mutex, OnceLock};

struct Singleton {
    data: String,
}

impl Singleton {
    fn new() -> Self {
        Singleton {
            data: "Singleton data".to_string(),
        }
    }
    
    fn instance() -> &'static Singleton {
        static INSTANCE: OnceLock<Singleton> = OnceLock::new();
        INSTANCE.get_or_init(|| Singleton::new())
    }
    
    fn get_data(&self) -> &str {
        &self.data
    }
    
    fn set_data(&mut self, data: String) {
        self.data = data;
    }
}

struct MutableSingleton {
    data: Arc<Mutex<String>>,
}

impl MutableSingleton {
    fn new() -> Self {
        MutableSingleton {
            data: Arc::new(Mutex::new("Mutable singleton data".to_string())),
        }
    }
    
    fn instance() -> Arc<Mutex<String>> {
        static INSTANCE: OnceLock<Arc<Mutex<String>>> = OnceLock::new();
        INSTANCE
            .get_or_init(|| Arc::new(Mutex::new("Mutable singleton data".to_string())))
            .clone()
    }
}

fn main() {
    let singleton = Singleton::instance();
    println!("{}", singleton.get_data());
    
    let data = MutableSingleton::instance();
    {
        let mut data = data.lock().unwrap();
        *data = "Updated data".to_string();
    }
    
    let data2 = MutableSingleton::instance();
    println!("{}", data2.lock().unwrap());
}
Coding Round
71. Factory pattern

Factory pattern using functions or trait objects.

  • Factory function: fn create_user(type: &str) -> Box<dyn User>
  • Match/if: Determine which type to create
  • Return: Box<dyn Trait> for polymorphism
  • Benefits: Decouples creation logic
rust
// Factory pattern in Rust
trait User {
    fn get_role(&self) -> &'static str;
}

struct Admin;
struct Guest;
struct RegularUser;

impl User for Admin {
    fn get_role(&self) -> &'static str {
        "admin"
    }
}

impl User for Guest {
    fn get_role(&self) -> &'static str {
        "guest"
    }
}

impl User for RegularUser {
    fn get_role(&self) -> &'static str {
        "regular"
    }
}

struct UserFactory;

impl UserFactory {
    fn create_user(user_type: &str) -> Box<dyn User> {
        match user_type {
            "admin" => Box::new(Admin),
            "guest" => Box::new(Guest),
            _ => Box::new(RegularUser),
        }
    }
}

fn main() {
    let admin = UserFactory::create_user("admin");
    let guest = UserFactory::create_user("guest");
    
    println!("Admin role: {}", admin.get_role());
    println!("Guest role: {}", guest.get_role());
}
Coding Round
72. Strategy pattern

Strategy pattern using trait objects or closures.

  • Trait: trait PaymentStrategy
  • Concrete strategies: Implement trait
  • Context: Uses strategy
  • Runtime switching: Change strategy at runtime
rust
// Strategy pattern in Rust
trait PaymentStrategy {
    fn pay(&self, amount: f64);
}

struct CreditCardStrategy;
struct PayPalStrategy;
struct CryptoStrategy;

impl PaymentStrategy for CreditCardStrategy {
    fn pay(&self, amount: f64) {
        println!("Paid $\{:.2} with Credit Card", amount);
    }
}

impl PaymentStrategy for PayPalStrategy {
    fn pay(&self, amount: f64) {
        println!("Paid $\{:.2} with PayPal", amount);
    }
}

impl PaymentStrategy for CryptoStrategy {
    fn pay(&self, amount: f64) {
        println!("Paid $\{:.2} with Crypto", amount);
    }
}

struct PaymentContext {
    strategy: Box<dyn PaymentStrategy>,
}

impl PaymentContext {
    fn new(strategy: Box<dyn PaymentStrategy>) -> Self {
        PaymentContext { strategy }
    }
    
    fn set_strategy(&mut self, strategy: Box<dyn PaymentStrategy>) {
        self.strategy = strategy;
    }
    
    fn execute_payment(&self, amount: f64) {
        self.strategy.pay(amount);
    }
}

fn main() {
    let mut context = PaymentContext::new(Box::new(CreditCardStrategy));
    context.execute_payment(100.0);
    
    context.set_strategy(Box::new(PayPalStrategy));
    context.execute_payment(50.0);
}
Coding Round
73. Observer pattern

Observer pattern with subject and observers using traits.

  • Observer trait: trait Observer { fn update(&self); }
  • Subject: Maintains observers
  • Attach/Detach: Add/remove observers
  • Notify: Call update on all observers
rust
// Observer pattern in Rust
trait Observer {
    fn update(&self, data: &str);
}

struct Subject {
    observers: Vec<Box<dyn Observer>>,
    state: String,
}

impl Subject {
    fn new() -> Self {
        Subject {
            observers: Vec::new(),
            state: String::new(),
        }
    }
    
    fn attach(&mut self, observer: Box<dyn Observer>) {
        self.observers.push(observer);
    }
    
    fn detach(&mut self, observer: &Box<dyn Observer>) {
        // In practice, we'd need to identify the observer
        // This is a simplified version
    }
    
    fn set_state(&mut self, state: String) {
        self.state = state;
        self.notify_observers();
    }
    
    fn notify_observers(&self) {
        for observer in &self.observers {
            observer.update(&self.state);
        }
    }
}

struct ConcreteObserver {
    name: String,
}

impl ConcreteObserver {
    fn new(name: String) -> Self {
        ConcreteObserver { name }
    }
}

impl Observer for ConcreteObserver {
    fn update(&self, data: &str) {
        println!("{} received: {}", self.name, data);
    }
}

fn main() {
    let mut subject = Subject::new();
    let observer1 = ConcreteObserver::new("Observer1".to_string());
    let observer2 = ConcreteObserver::new("Observer2".to_string());
    
    subject.attach(Box::new(observer1));
    subject.attach(Box::new(observer2));
    
    subject.set_state("Hello World".to_string());
}
Coding Round
74. Decorator pattern

Decorator pattern using wrapper functions or structs.

  • Component: Base object
  • Decorator: Wraps component
  • Chaining: Multiple decorators
  • Benefits: Add behavior dynamically
rust
// Decorator pattern in Rust
#[derive(Clone)]
struct Coffee {
    cost: f64,
    description: String,
}

impl Coffee {
    fn new() -> Self {
        Coffee {
            cost: 5.0,
            description: "Coffee".to_string(),
        }
    }
}

trait CoffeeDecorator {
    fn decorate(&self, coffee: Coffee) -> Coffee;
}

struct MilkDecorator;
struct SugarDecorator;
struct WhippedCreamDecorator;

impl CoffeeDecorator for MilkDecorator {
    fn decorate(&self, coffee: Coffee) -> Coffee {
        Coffee {
            cost: coffee.cost + 2.0,
            description: format!("{}, Milk", coffee.description),
        }
    }
}

impl CoffeeDecorator for SugarDecorator {
    fn decorate(&self, coffee: Coffee) -> Coffee {
        Coffee {
            cost: coffee.cost + 1.0,
            description: format!("{}, Sugar", coffee.description),
        }
    }
}

impl CoffeeDecorator for WhippedCreamDecorator {
    fn decorate(&self, coffee: Coffee) -> Coffee {
        Coffee {
            cost: coffee.cost + 1.5,
            description: format!("{}, Whipped Cream", coffee.description),
        }
    }
}

fn main() {
    let coffee = Coffee::new();
    let coffee = MilkDecorator.decorate(coffee);
    let coffee = SugarDecorator.decorate(coffee);
    let coffee = WhippedCreamDecorator.decorate(coffee);
    
    println!("Description: {}", coffee.description);
    println!("Cost: $\{:.2}", coffee.cost);
}
Coding Round
75. Command pattern

Command pattern with execute and undo methods using traits.

  • Command trait: trait Command { fn execute(&mut self); fn undo(&mut self); }
  • Receiver: Performs actual work
  • Invoker: Executes commands
  • Undo/Redo: Command history
rust
// Command pattern in Rust
trait Command {
    fn execute(&mut self);
    fn undo(&mut self);
}

struct AddCommand {
    receiver: Vec<i32>,
    value: i32,
}

impl AddCommand {
    fn new(receiver: Vec<i32>, value: i32) -> Self {
        AddCommand { receiver, value }
    }
}

impl Command for AddCommand {
    fn execute(&mut self) {
        self.receiver.push(self.value);
    }
    
    fn undo(&mut self) {
        if let Some(pos) = self.receiver.iter().position(|&x| x == self.value) {
            self.receiver.remove(pos);
        }
    }
}

struct CommandManager {
    history: Vec<Box<dyn Command>>,
    redo_stack: Vec<Box<dyn Command>>,
}

impl CommandManager {
    fn new() -> Self {
        CommandManager {
            history: Vec::new(),
            redo_stack: Vec::new(),
        }
    }
    
    fn execute(&mut self, mut command: Box<dyn Command>) {
        command.execute();
        self.history.push(command);
        self.redo_stack.clear();
    }
    
    fn undo(&mut self) {
        if let Some(mut command) = self.history.pop() {
            command.undo();
            self.redo_stack.push(command);
        }
    }
    
    fn redo(&mut self) {
        if let Some(mut command) = self.redo_stack.pop() {
            command.execute();
            self.history.push(command);
        }
    }
}

fn main() {
    let receiver = vec![1, 2, 3];
    let mut manager = CommandManager::new();
    
    let cmd = AddCommand::new(receiver.clone(), 4);
    manager.execute(Box::new(cmd));
    manager.undo();
}
Coding Round
76. Memento pattern

Memento pattern for state capture and restoration using Clone.

  • Originator: Creates and restores mementos
  • Memento: Stores state
  • Caretaker: Manages mementos
  • Undo/Redo: State history
rust
// Memento pattern in Rust
#[derive(Clone)]
struct Memento {
    state: String,
}

struct Originator {
    state: String,
}

impl Originator {
    fn new() -> Self {
        Originator {
            state: String::new(),
        }
    }
    
    fn save_state(&self) -> Memento {
        Memento {
            state: self.state.clone(),
        }
    }
    
    fn restore_state(&mut self, memento: Memento) {
        self.state = memento.state;
    }
}

struct Caretaker {
    mementos: Vec<Memento>,
}

impl Caretaker {
    fn new() -> Self {
        Caretaker {
            mementos: Vec::new(),
        }
    }
    
    fn add_memento(&mut self, memento: Memento) {
        self.mementos.push(memento);
    }
    
    fn get_memento(&self, index: usize) -> Option<&Memento> {
        self.mementos.get(index)
    }
}

fn main() {
    let mut originator = Originator::new();
    let mut caretaker = Caretaker::new();
    
    originator.state = "State 1".to_string();
    caretaker.add_memento(originator.save_state());
    
    originator.state = "State 2".to_string();
    caretaker.add_memento(originator.save_state());
    
    originator.state = "State 3".to_string();
    
    if let Some(memento) = caretaker.get_memento(0) {
        originator.restore_state(memento.clone());
        println!("Restored state: {}", originator.state);
    }
}
Coding Round
77. Mediator pattern

Mediator pattern for centralized communication using structs.

  • Mediator: Encapsulates communication
  • Colleague: Communicates through mediator
  • Benefits: Loose coupling
  • Use case: Chat systems
rust
// Mediator pattern in Rust
struct Mediator {
    colleagues: Vec<Colleague>,
}

impl Mediator {
    fn new() -> Self {
        Mediator {
            colleagues: Vec::new(),
        }
    }
    
    fn register(&mut self, colleague: Colleague) {
        self.colleagues.push(colleague);
    }
    
    fn send(&self, message: &str, sender: &Colleague) {
        for colleague in &self.colleagues {
            if colleague.id != sender.id {
                colleague.receive(message);
            }
        }
    }
}

struct Colleague {
    id: usize,
    name: String,
}

impl Colleague {
    fn new(id: usize, name: String) -> Self {
        Colleague { id, name }
    }
    
    fn send(&self, mediator: &Mediator, message: &str) {
        mediator.send(message, self);
    }
    
    fn receive(&self, message: &str) {
        println!("{} received: {}", self.name, message);
    }
}

fn main() {
    let mut mediator = Mediator::new();
    let alice = Colleague::new(1, "Alice".to_string());
    let bob = Colleague::new(2, "Bob".to_string());
    
    mediator.register(alice);
    mediator.register(bob);
    
    // In practice, we'd need to keep references to the colleagues
    // This is a simplified version
}
Coding Round
78. Chain of Responsibility

Chain of Responsibility for processing requests sequentially using traits.

  • Handler trait: trait Handler { fn handle(&self, request: &Request) -> Option<String>; }
  • Chain: Vector of handlers
  • Benefits: Decoupling
  • Use case: Logging, authentication
rust
// Chain of Responsibility in Rust
trait Handler {
    fn handle(&self, request: &Request) -> Option<String>;
}

struct Request {
    token: Option<String>,
    url: String,
    permissions: Vec<String>,
}

struct AuthHandler;
struct LoggerHandler;
struct PermissionHandler;

impl Handler for AuthHandler {
    fn handle(&self, request: &Request) -> Option<String> {
        if request.token.is_some() {
            Some("Authentication passed".to_string())
        } else {
            Some("Authentication failed".to_string())
        }
    }
}

impl Handler for LoggerHandler {
    fn handle(&self, request: &Request) -> Option<String> {
        Some(format!("Logging request: {}", request.url))
    }
}

impl Handler for PermissionHandler {
    fn handle(&self, request: &Request) -> Option<String> {
        if request.permissions.contains(&"read".to_string()) {
            Some("Permission granted".to_string())
        } else {
            Some("Permission denied".to_string())
        }
    }
}

struct Chain {
    handlers: Vec<Box<dyn Handler>>,
}

impl Chain {
    fn new() -> Self {
        Chain {
            handlers: Vec::new(),
        }
    }
    
    fn add_handler(&mut self, handler: Box<dyn Handler>) {
        self.handlers.push(handler);
    }
    
    fn handle(&self, request: &Request) -> Vec<String> {
        let mut responses = Vec::new();
        for handler in &self.handlers {
            if let Some(response) = handler.handle(request) {
                responses.push(response);
            }
        }
        responses
    }
}

fn main() {
    let mut chain = Chain::new();
    chain.add_handler(Box::new(AuthHandler));
    chain.add_handler(Box::new(LoggerHandler));
    chain.add_handler(Box::new(PermissionHandler));
    
    let request = Request {
        token: Some("valid".to_string()),
        url: "/api/data".to_string(),
        permissions: vec!["read".to_string()],
    };
    
    let responses = chain.handle(&request);
    for response in responses {
        println!("{}", response);
    }
}
Coding Round
79. State pattern

State pattern for changing behavior with state using trait objects.

  • State trait: trait State { fn handle(&self, context: &mut Context); }
  • Context: Maintains state
  • Transitions: Change between states
  • Benefits: Clean state management
rust
// State pattern in Rust
trait State {
    fn handle(&self, context: &mut Context);
}

struct ReadyState;
struct ProcessingState;
struct CompletedState;

impl State for ReadyState {
    fn handle(&self, context: &mut Context) {
        println!("Ready: Waiting for input");
        context.state = Box::new(ProcessingState);
    }
}

impl State for ProcessingState {
    fn handle(&self, context: &mut Context) {
        println!("Processing: Working on task");
        context.state = Box::new(CompletedState);
    }
}

impl State for CompletedState {
    fn handle(&self, _context: &mut Context) {
        println!("Completed: Task finished");
    }
}

struct Context {
    state: Box<dyn State>,
}

impl Context {
    fn new() -> Self {
        Context {
            state: Box::new(ReadyState),
        }
    }
    
    fn request(&mut self) {
        self.state.handle(self);
    }
}

fn main() {
    let mut context = Context::new();
    context.request();
    context.request();
    context.request();
}
Coding Round
80. Proxy pattern

Proxy pattern for controlling access to objects using traits.

  • Subject trait: trait Subject { fn request(&self); }
  • Proxy: Controls access
  • Lazy loading: Create on demand
  • Benefits: Access control, logging
rust
// Proxy pattern in Rust
trait Subject {
    fn request(&self);
}

struct RealSubject;

impl Subject for RealSubject {
    fn request(&self) {
        println!("RealSubject: Handling request");
    }
}

struct Proxy {
    real_subject: Option<RealSubject>,
}

impl Proxy {
    fn new() -> Self {
        Proxy {
            real_subject: None,
        }
    }
}

impl Subject for Proxy {
    fn request(&self) {
        if self.check_access() {
            if self.real_subject.is_none() {
                // In practice, we'd need interior mutability
                // This is a simplified version
            }
            println!("Proxy: Forwarding request");
        }
    }
}

impl Proxy {
    fn check_access(&self) -> bool {
        println!("Proxy: Checking access");
        true
    }
}

fn main() {
    let proxy = Proxy::new();
    proxy.request();
}
Coding Round
81. Flyweight pattern

Flyweight pattern for sharing objects to save memory using HashMap.

  • Flyweight: Shared object
  • Factory: Manages flyweights
  • Benefits: Memory optimization
  • Use case: Character rendering
rust
// Flyweight pattern in Rust
use std::collections::HashMap;

struct Flyweight {
    shared_state: String,
}

impl Flyweight {
    fn new(shared_state: String) -> Self {
        Flyweight { shared_state }
    }
    
    fn operation(&self, unique_state: &str) {
        println!("Shared: {}, Unique: {}", self.shared_state, unique_state);
    }
}

struct FlyweightFactory {
    flyweights: HashMap<String, Flyweight>,
}

impl FlyweightFactory {
    fn new() -> Self {
        FlyweightFactory {
            flyweights: HashMap::new(),
        }
    }
    
    fn get_flyweight(&mut self, shared_state: String) -> &Flyweight {
        self.flyweights
            .entry(shared_state.clone())
            .or_insert_with(|| {
                println!("Creating new flyweight for: {}", shared_state);
                Flyweight::new(shared_state)
            })
    }
}

fn main() {
    let mut factory = FlyweightFactory::new();
    let fw1 = factory.get_flyweight("state1".to_string());
    let fw2 = factory.get_flyweight("state1".to_string());
    let fw3 = factory.get_flyweight("state2".to_string());
    
    fw1.operation("unique1");
    fw2.operation("unique2");
    fw3.operation("unique3");
}
Coding Round
82. Bridge pattern

Bridge pattern for separating abstraction from implementation using traits.

  • Implementation trait: trait Implementation
  • Abstraction: High-level interface
  • Benefits: Separation of concerns
  • Use case: Cross-platform
rust
// Bridge pattern in Rust
trait Implementation {
    fn operation_impl(&self);
}

struct ConcreteImplementationA;
struct ConcreteImplementationB;

impl Implementation for ConcreteImplementationA {
    fn operation_impl(&self) {
        println!("ConcreteImplementationA: Operation");
    }
}

impl Implementation for ConcreteImplementationB {
    fn operation_impl(&self) {
        println!("ConcreteImplementationB: Operation");
    }
}

struct Abstraction {
    impl_: Box<dyn Implementation>,
}

impl Abstraction {
    fn new(impl_: Box<dyn Implementation>) -> Self {
        Abstraction { impl_ }
    }
    
    fn operation(&self) {
        println!("Abstraction: Additional logic");
        self.impl_.operation_impl();
    }
}

fn main() {
    let impl_a = ConcreteImplementationA;
    let impl_b = ConcreteImplementationB;
    let abstraction1 = Abstraction::new(Box::new(impl_a));
    let abstraction2 = Abstraction::new(Box::new(impl_b));
    
    abstraction1.operation();
    abstraction2.operation();
}
Coding Round
83. Adapter pattern

Adapter pattern for converting interfaces using structs.

  • Target: Expected interface
  • Adaptee: Existing interface
  • Adapter: Bridges interfaces
  • Benefits: Reusability
rust
// Adapter pattern in Rust
trait Target {
    fn request(&self);
}

struct Adaptee;

impl Adaptee {
    fn specific_request(&self) {
        println!("Adaptee: Specific Request");
    }
}

struct Adapter {
    adaptee: Adaptee,
}

impl Adapter {
    fn new(adaptee: Adaptee) -> Self {
        Adapter { adaptee }
    }
}

impl Target for Adapter {
    fn request(&self) {
        self.adaptee.specific_request();
    }
}

fn main() {
    let adaptee = Adaptee;
    let adapter = Adapter::new(adaptee);
    adapter.request();
}
Coding Round
84. Facade pattern

Facade pattern for simplifying complex subsystems using structs.

  • Facade: Simplified interface
  • Subsystem: Complex components
  • Benefits: Simplified interface
  • Use case: Library APIs
rust
// Facade pattern in Rust
struct SubsystemA;
struct SubsystemB;
struct SubsystemC;

impl SubsystemA {
    fn operation_a(&self) {
        println!("SubsystemA: Operation");
    }
}

impl SubsystemB {
    fn operation_b(&self) {
        println!("SubsystemB: Operation");
    }
}

impl SubsystemC {
    fn operation_c(&self) {
        println!("SubsystemC: Operation");
    }
}

struct Facade {
    subsystem_a: SubsystemA,
    subsystem_b: SubsystemB,
    subsystem_c: SubsystemC,
}

impl Facade {
    fn new() -> Self {
        Facade {
            subsystem_a: SubsystemA,
            subsystem_b: SubsystemB,
            subsystem_c: SubsystemC,
        }
    }
    
    fn operation(&self) {
        println!("Facade: Complex operation");
        self.subsystem_a.operation_a();
        self.subsystem_b.operation_b();
        self.subsystem_c.operation_c();
    }
}

fn main() {
    let facade = Facade::new();
    facade.operation();
}
Coding Round
85. Composite pattern

Composite pattern for tree structures using trait objects.

  • Component trait: trait Component { fn operation(&self); }
  • Leaf: Individual object
  • Composite: Container
  • Benefits: Uniform interface
rust
// Composite pattern in Rust
trait Component {
    fn operation(&self);
}

struct Leaf {
    name: String,
}

impl Leaf {
    fn new(name: String) -> Self {
        Leaf { name }
    }
}

impl Component for Leaf {
    fn operation(&self) {
        println!("Leaf {}: Operation", self.name);
    }
}

struct Composite {
    name: String,
    children: Vec<Box<dyn Component>>,
}

impl Composite {
    fn new(name: String) -> Self {
        Composite {
            name,
            children: Vec::new(),
        }
    }
    
    fn add(&mut self, component: Box<dyn Component>) {
        self.children.push(component);
    }
    
    fn remove(&mut self, component: Box<dyn Component>) {
        // In practice, we'd need to identify the component
        // This is a simplified version
    }
}

impl Component for Composite {
    fn operation(&self) {
        println!("Composite {}: Operation", self.name);
        for child in &self.children {
            child.operation();
        }
    }
}

fn main() {
    let leaf1 = Leaf::new("A".to_string());
    let leaf2 = Leaf::new("B".to_string());
    let mut composite = Composite::new("Root".to_string());
    
    composite.add(Box::new(leaf1));
    composite.add(Box::new(leaf2));
    composite.operation();
}
Coding Round
86. Visitor pattern

Visitor pattern for adding operations without modifying elements using traits.

  • Visitor trait: trait Visitor
  • Element trait: trait Element { fn accept(&self, visitor: &dyn Visitor); }
  • Benefits: Adding operations without modifying
  • Use case: Compilers, AST
rust
// Visitor pattern in Rust
trait Visitor {
    fn visit_element_a(&self, element: &ElementA);
    fn visit_element_b(&self, element: &ElementB);
}

trait Element {
    fn accept(&self, visitor: &dyn Visitor);
}

struct ElementA;
struct ElementB;

impl Element for ElementA {
    fn accept(&self, visitor: &dyn Visitor) {
        visitor.visit_element_a(self);
    }
}

impl Element for ElementB {
    fn accept(&self, visitor: &dyn Visitor) {
        visitor.visit_element_b(self);
    }
}

struct ConcreteVisitor;

impl Visitor for ConcreteVisitor {
    fn visit_element_a(&self, _element: &ElementA) {
        println!("Visiting ElementA");
    }
    
    fn visit_element_b(&self, _element: &ElementB) {
        println!("Visiting ElementB");
    }
}

fn main() {
    let visitor = ConcreteVisitor;
    let element_a = ElementA;
    let element_b = ElementB;
    
    element_a.accept(&visitor);
    element_b.accept(&visitor);
}
Coding Round
87. Iterator pattern

Iterator pattern for sequential access using Iterator trait.

  • Iterator trait: impl Iterator for CustomIterator
  • Aggregate: Creates iterator
  • Benefits: Uniform traversal
  • Use case: Collection traversal
rust
// Iterator pattern in Rust
struct CustomIterator<T> {
    collection: Vec<T>,
    index: usize,
}

impl<T: Clone> CustomIterator<T> {
    fn new(collection: Vec<T>) -> Self {
        CustomIterator {
            collection,
            index: 0,
        }
    }
    
    fn next(&mut self) -> Option<T> {
        if self.index < self.collection.len() {
            let item = self.collection[self.index].clone();
            self.index += 1;
            Some(item)
        } else {
            None
        }
    }
    
    fn has_next(&self) -> bool {
        self.index < self.collection.len()
    }
}

fn main() {
    let collection = vec![1, 2, 3, 4, 5];
    let mut iterator = CustomIterator::new(collection);
    
    while iterator.has_next() {
        println!("{}", iterator.next().unwrap());
    }
}
Coding Round
88. Template Method pattern

Template Method for algorithm skeletons using traits.

  • Abstract trait: trait AbstractClass { fn template_method(&self); }
  • Concrete: Implements steps
  • Benefits: Code reuse
  • Use case: Frameworks
rust
// Template Method pattern in Rust
trait AbstractClass {
    fn template_method(&self) {
        self.step1();
        self.step2();
        self.step3();
    }
    
    fn step1(&self) {
        println!("Step 1");
    }
    
    fn step2(&self);
    
    fn step3(&self) {
        println!("Step 3");
    }
}

struct ConcreteClass;

impl AbstractClass for ConcreteClass {
    fn step2(&self) {
        println!("Concrete Step 2");
    }
}

fn main() {
    let concrete = ConcreteClass;
    concrete.template_method();
}
Coding Round
89. Builder pattern

Builder pattern for constructing complex objects using structs.

  • Builder: Constructs parts
  • Director: Orchestrates construction
  • Product: Constructed object
  • Benefits: Step-by-step construction
rust
// Builder pattern in Rust
struct Product {
    parts: Vec<String>,
}

impl Product {
    fn new() -> Self {
        Product {
            parts: Vec::new(),
        }
    }
    
    fn add(&mut self, part: String) {
        self.parts.push(part);
    }
    
    fn list_parts(&self) {
        println!("{}", self.parts.join(", "));
    }
}

struct Builder {
    product: Product,
}

impl Builder {
    fn new() -> Self {
        Builder {
            product: Product::new(),
        }
    }
    
    fn reset(&mut self) {
        self.product = Product::new();
    }
    
    fn build_step_a(&mut self) {
        self.product.add("Part A".to_string());
    }
    
    fn build_step_b(&mut self) {
        self.product.add("Part B".to_string());
    }
    
    fn get_result(&self) -> &Product {
        &self.product
    }
}

struct Director {
    builder: Builder,
}

impl Director {
    fn new(builder: Builder) -> Self {
        Director { builder }
    }
    
    fn build_minimal(&mut self) {
        self.builder.build_step_a();
    }
    
    fn build_full(&mut self) {
        self.builder.build_step_a();
        self.builder.build_step_b();
    }
}

fn main() {
    let mut builder = Builder::new();
    let mut director = Director::new(builder);
    director.build_minimal();
    director.builder.get_result().list_parts();
}
Coding Round
90. Prototype pattern

Prototype pattern for cloning objects using Clone trait.

  • Clone trait: #[derive(Clone)]
  • Shallow copy: clone()
  • Deep copy: Manual recursive clone
  • Benefits: Object reuse, performance
rust
// Prototype pattern in Rust
#[derive(Clone)]
struct Prototype {
    name: String,
    nested: std::collections::HashMap<String, i32>,
}

impl Prototype {
    fn new(name: String, nested: std::collections::HashMap<String, i32>) -> Self {
        Prototype { name, nested }
    }
    
    fn clone_prototype(&self) -> Self {
        self.clone()
    }
    
    fn deep_clone(&self) -> Self {
        Prototype {
            name: self.name.clone(),
            nested: self.nested.clone(),
        }
    }
}

fn main() {
    let mut nested = std::collections::HashMap::new();
    nested.insert("value".to_string(), 42);
    
    let original = Prototype::new("Original".to_string(), nested);
    let copy = original.clone_prototype();
    let deep_copy = original.deep_clone();
    
    println!("Original name: {}", original.name);
    println!("Copy name: {}", copy.name);
}
Coding Round
91. Error Handling with anyhow/thiserror

Error handling using anyhow and thiserror crates for better error management.

  • thiserror: Define custom errors
  • anyhow: Contextual error handling
  • Result: Result<T, anyhow::Error>
  • Error chaining: .context("message")
rust
// Error Handling with anyhow and thiserror
use anyhow::{anyhow, Result};
use thiserror::Error;

#[derive(Error, Debug)]
enum MyError {
    #[error("Invalid age: {0}")]
    InvalidAge(i32),
    
    #[error("IO error: {0}")]
    IoError(#[from] std::io::Error),
}

fn validate_age(age: i32) -> Result<(), MyError> {
    if age < 0 || age > 150 {
        return Err(MyError::InvalidAge(age));
    }
    Ok(())
}

fn process_data() -> Result<String> {
    let result = validate_age(200)
        .map_err(|e| anyhow!("Validation failed: {}", e))?;
    Ok("Data processed".to_string())
}

fn main() -> Result<()> {
    match process_data() {
        Ok(data) => println!("{}", data),
        Err(e) => println!("Error: {}", e),
    }
    Ok(())
}
Coding Round
92. Serialization with Serde

Serialization using serde for JSON, YAML, and other formats.

  • Serialize: #[derive(Serialize)]
  • Deserialize: #[derive(Deserialize)]
  • JSON: serde_json
  • Custom serialization: serialize_with
rust
// Serialization with Serde
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug)]
struct Person {
    name: String,
    age: u32,
    email: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct PersonWithOptional {
    name: String,
    age: u32,
    #[serde(default)]
    email: Option<String>,
    #[serde(default = "default_city")]
    city: String,
}

fn default_city() -> String {
    "Unknown".to_string()
}

fn main() -> Result<(), serde_json::Error> {
    let person = Person {
        name: "Alice".to_string(),
        age: 25,
        email: "alice@example.com".to_string(),
    };
    
    let json = serde_json::to_string(&person)?;
    println!("Serialized: {}", json);
    
    let deserialized: Person = serde_json::from_str(&json)?;
    println!("Deserialized: {:?}", deserialized);
    
    // With optional fields
    let person2 = PersonWithOptional {
        name: "Bob".to_string(),
        age: 30,
        email: None,
        city: "NYC".to_string(),
    };
    
    let json2 = serde_json::to_string(&person2)?;
    println!("Serialized with optional: {}", json2);
    
    Ok(())
}
Coding Round
93. Concurrency with Threads

Concurrency using std::thread and Arc<Mutex> for shared state.

  • Thread spawn: thread::spawn(|| )
  • Shared state: Arc<Mutex<T>>
  • Join: handle.join()
  • Message passing: mpsc::channel()
rust
// Concurrency with threads
use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    // Thread with move
    let handle = thread::spawn(|| {
        for i in 1..5 {
            println!("Thread: {}", i);
            thread::sleep(std::time::Duration::from_millis(100));
        }
    });
    
    for i in 1..3 {
        println!("Main: {}", i);
        thread::sleep(std::time::Duration::from_millis(150));
    }
    
    handle.join().unwrap();
    
    // Shared state with Mutex
    let counter = Arc::new(Mutex::new(0));
    let mut handles = vec![];
    
    for _ in 0..10 {
        let counter = Arc::clone(&counter);
        let handle = thread::spawn(move || {
            let mut num = counter.lock().unwrap();
            *num += 1;
        });
        handles.push(handle);
    }
    
    for handle in handles {
        handle.join().unwrap();
    }
    
    println!("Result: {}", *counter.lock().unwrap());
}
Coding Round
94. Async with Tokio

Asynchronous programming using tokio runtime.

  • Runtime: #[tokio::main]
  • Tasks: tokio::spawn(async )
  • Join: tokio::try_join!
  • Timeout: tokio::time::timeout
rust
// Async with Tokio
use tokio::time::{sleep, Duration};
use tokio::task;

#[tokio::main]
async fn main() {
    // Basic async
    let handle = task::spawn(async {
        sleep(Duration::from_secs(1)).await;
        println!("Task completed");
    });
    
    handle.await.unwrap();
    
    // Parallel tasks
    let task1 = task::spawn(async {
        sleep(Duration::from_secs(1)).await;
        "Task 1"
    });
    
    let task2 = task::spawn(async {
        sleep(Duration::from_millis(500)).await;
        "Task 2"
    });
    
    let results = tokio::try_join!(task1, task2).unwrap();
    println!("Results: {:?}", results);
    
    // Timeout
    let result = tokio::time::timeout(
        Duration::from_millis(500),
        async {
            sleep(Duration::from_secs(1)).await;
            "Success"
        }
    ).await;
    
    match result {
        Ok(data) => println!("Success: {}", data),
        Err(_) => println!("Timeout!"),
    }
}
Coding Round
95. Testing in Rust

Testing using #[test] attributes and assert macros.

  • Test attribute: #[test]
  • Assertions: assert_eq!, assert_ne!
  • Should panic: #[should_panic]
  • Async tests: #[tokio::test]
rust
// Testing in Rust
#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_add() {
        assert_eq!(add(2, 3), 5);
        assert_eq!(add(-1, 1), 0);
    }
    
    #[test]
    fn test_divide() -> Result<(), String> {
        let result = divide(10, 2)?;
        assert_eq!(result, 5);
        Ok(())
    }
    
    #[test]
    #[should_panic(expected = "Division by zero")]
    fn test_divide_by_zero() {
        divide(10, 0).unwrap();
    }
    
    #[tokio::test]
    async fn test_async() {
        let result = async_function().await;
        assert_eq!(result, "Success");
    }
}

fn add(a: i32, b: i32) -> i32 {
    a + b
}

fn divide(a: i32, b: i32) -> Result<i32, &'static str> {
    if b == 0 {
        Err("Division by zero")
    } else {
        Ok(a / b)
    }
}

async fn async_function() -> &'static str {
    "Success"
}
Coding Round
96. Closures and Iterators Advanced

Advanced closures with captured variables and iterator adapters.

  • Move closures: move ||
  • Iterator adapters: map, filter, fold
  • Any/All: any(), all()
  • Closure traits: Fn, FnMut, FnOnce
rust
// Closures and Iterators Advanced
fn main() {
    // Closure with captured variables
    let factor = 2;
    let multiply = |x: i32| x * factor;
    println!("Multiply: {}", multiply(5));
    
    // Closure with move
    let numbers = vec![1, 2, 3];
    let process = move |x: i32| {
        numbers.iter().map(|&n| n * x).collect::<Vec<i32>>()
    };
    println!("Processed: {:?}", process(2));
    
    // Iterator adapters
    let data = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    let result: Vec<i32> = data
        .iter()
        .skip(2)
        .take(5)
        .filter(|&&x| x % 2 == 0)
        .map(|&x| x * x)
        .collect();
    println!("Result: {:?}", result);
    
    // Fold (reduce)
    let sum = data.iter().fold(0, |acc, &x| acc + x);
    println!("Sum: {}", sum);
    
    // Any/All
    let any_even = data.iter().any(|&x| x % 2 == 0);
    let all_even = data.iter().all(|&x| x % 2 == 0);
    println!("Any even: {}, All even: {}", any_even, all_even);
}
Coding Round
97. Smart Pointers

Smart pointers in Rust: Box, Rc, Arc, RefCell, and Weak.

  • Box: Heap allocation
  • Rc: Reference counting (single-threaded)
  • Arc: Atomic reference counting (multi-threaded)
  • RefCell: Interior mutability
  • Weak: Weak references to avoid cycles
rust
// Smart Pointers in Rust
use std::rc::Rc;
use std::cell::RefCell;

// Rc (Reference Counting)
fn rc_example() {
    let data = Rc::new(42);
    let data2 = Rc::clone(&data);
    let data3 = Rc::clone(&data);
    
    println!("Rc count: {}", Rc::strong_count(&data));
    println!("Value: {}", data);
}

// RefCell (Interior Mutability)
fn refcell_example() {
    let data = RefCell::new(42);
    *data.borrow_mut() = 100;
    println!("Value: {}", data.borrow());
}

// Rc + RefCell combination
fn rc_refcell_example() {
    let shared_data = Rc::new(RefCell::new(42));
    let data2 = Rc::clone(&shared_data);
    let data3 = Rc::clone(&shared_data);
    
    *data2.borrow_mut() = 100;
    println!("Value: {}", data3.borrow());
}

// Weak references
use std::rc::Weak;

struct Node {
    value: i32,
    parent: RefCell<Weak<Node>>,
    children: RefCell<Vec<Rc<Node>>>,
}

fn weak_example() {
    let parent = Rc::new(Node {
        value: 1,
        parent: RefCell::new(Weak::new()),
        children: RefCell::new(Vec::new()),
    });
    
    let child = Rc::new(Node {
        value: 2,
        parent: RefCell::new(Rc::downgrade(&parent)),
        children: RefCell::new(Vec::new()),
    });
    
    parent.children.borrow_mut().push(child);
    
    println!("Parent value: {}", parent.value);
    println!("Parent children count: {}", parent.children.borrow().len());
}

fn main() {
    rc_example();
    refcell_example();
    rc_refcell_example();
    weak_example();
}
Coding Round
98. Lifetimes in Rust

Lifetimes ensure references are valid and prevent dangling references.

  • Lifetime annotations: 'a
  • Multiple lifetimes: 'a, 'b
  • Lifetime elision: Compiler can infer
  • Static lifetime: 'static
rust
// Lifetimes in Rust
// Lifetimes ensure references are valid
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

// Struct with lifetimes
struct Person<'a> {
    name: &'a str,
    age: u32,
}

impl<'a> Person<'a> {
    fn new(name: &'a str, age: u32) -> Self {
        Person { name, age }
    }
    
    fn get_name(&self) -> &str {
        self.name
    }
}

// Multiple lifetimes
struct Pair<'a, 'b> {
    first: &'a str,
    second: &'b str,
}

// Lifetime elision
fn first_word(s: &str) -> &str {
    s.split_whitespace().next().unwrap_or("")
}

// Static lifetime
const STATIC_STR: &'static str = "This has a static lifetime";

fn main() {
    let string1 = String::from("long string");
    let string2 = "short";
    
    let result = longest(&string1, string2);
    println!("Longest: {}", result);
    
    let name = String::from("Alice");
    let person = Person::new(&name, 25);
    println!("Person: {}", person.get_name());
    
    let word = first_word("Hello World");
    println!("First word: {}", word);
    
    println!("Static string: {}", STATIC_STR);
}
Coding Round
99. Unsafe Rust

Unsafe Rust allows operations that the compiler can't verify, like raw pointers and FFI.

  • Unsafe block: unsafe
  • Raw pointers: *const T, *mut T
  • FFI: extern "C"
  • Safe abstractions: Wrapping unsafe in safe APIs
rust
// Unsafe Rust
fn main() {
    // Raw pointers
    let x = 42;
    let raw_ptr = &x as *const i32;
    unsafe {
        println!("Raw pointer value: {}", *raw_ptr);
    }
    
    // Mutable raw pointer
    let mut y = 10;
    let raw_mut_ptr = &mut y as *mut i32;
    unsafe {
        *raw_mut_ptr = 20;
    }
    println!("Modified value: {}", y);
    
    // Calling unsafe function
    unsafe fn dangerous() {
        println!("This is an unsafe function");
    }
    unsafe {
        dangerous();
    }
    
    // Using unsafe block for FFI
    #[cfg(target_os = "windows")]
    unsafe {
        // Windows API calls
    }
    
    // Safe abstraction over unsafe
    use std::slice;
    
    fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
        let len = slice.len();
        let ptr = slice.as_mut_ptr();
        
        unsafe {
            assert!(mid <= len);
            (
                slice::from_raw_parts_mut(ptr, mid),
                slice::from_raw_parts_mut(ptr.add(mid), len - mid),
            )
        }
    }
    
    let mut numbers = vec![1, 2, 3, 4, 5];
    let (left, right) = split_at_mut(&mut numbers, 2);
    println!("Left: {:?}, Right: {:?}", left, right);
}
Coding Round
100. FFI and C Interop

Foreign Function Interface for calling C functions and exposing Rust functions to C.

  • extern "C": Declare C functions
  • #[no_mangle]: Prevent name mangling
  • repr(C): C-compatible struct layout
  • CString: Convert between Rust and C strings
rust
// FFI and C Interop
use std::ffi::CString;
use std::os::raw::c_char;

// Declare external C function
extern "C" {
    fn printf(format: *const c_char, ...) -> i32;
}

// C-compatible struct
#[repr(C)]
struct Point {
    x: f64,
    y: f64,
}

// Export function to C
#[no_mangle]
pub extern "C" fn add_numbers(a: i32, b: i32) -> i32 {
    a + b
}

#[no_mangle]
pub extern "C" fn create_point(x: f64, y: f64) -> *mut Point {
    Box::into_raw(Box::new(Point { x, y }))
}

#[no_mangle]
pub extern "C" fn free_point(ptr: *mut Point) {
    if !ptr.is_null() {
        unsafe { drop(Box::from_raw(ptr)); }
    }
}

#[no_mangle]
pub extern "C" fn get_point_x(ptr: *const Point) -> f64 {
    unsafe { (*ptr).x }
}

#[no_mangle]
pub extern "C" fn get_point_y(ptr: *const Point) -> f64 {
    unsafe { (*ptr).y }
}

// Safe wrapper
fn call_printf() {
    let format = CString::new("Hello from printf: %d\n").unwrap();
    unsafe {
        printf(format.as_ptr(), 42);
    }
}

fn main() {
    // Call C function
    call_printf();
    
    // Use exported function
    let result = add_numbers(5, 3);
    println!("Add numbers: {}", result);
    
    // Use point functions
    let point_ptr = create_point(10.0, 20.0);
    unsafe {
        println!("Point x: {}, y: {}", get_point_x(point_ptr), get_point_y(point_ptr));
        free_point(point_ptr);
    }
}