Title: Rust Programming — LearnCoachAssist

Q: What is Rust?
A: Rust is a systems programming language focused on safety, speed, and concurrency. It achieves memory safety without a garbage collector through its ownership system.

Q: What is ownership in Rust?
A: Ownership is Rust's core memory management concept. Each value has exactly one owner, and when the owner goes out of scope, the value is dropped (freed). This prevents memory leaks and double frees at compile time.

Q: What are the three ownership rules in Rust?
A: - Each value in Rust has a single owner
- There can only be one owner at a time
- When the owner goes out of scope, the value is dropped

Q: What is borrowing in Rust?
A: Borrowing lets you reference a value without taking ownership. You create a reference with &. The original owner retains ownership while the borrower can read (or write, if mutable) the data.

Q: What is the difference between &T and &mut T?
A: &T is an immutable reference (shared borrow) — multiple allowed simultaneously.
&mut T is a mutable reference (exclusive borrow) — only one allowed at a time, and no immutable references may coexist with it.

Q: What is a lifetime in Rust?
A: A lifetime is a compile-time annotation (e.g., 'a) that tells the compiler how long a reference is valid. Lifetimes prevent dangling references by ensuring borrowed data outlives the borrower.

Q: How do you annotate lifetimes on a function?
A: Use lifetime parameters in angle brackets: fn longest<'a>(x: &'a str, y: &'a str) -> &'a str. This tells the compiler the returned reference lives at least as long as the shorter of x and y.

Q: What is the 'static lifetime?
A: 'static means the reference is valid for the entire duration of the program. String literals have type &'static str because they are embedded in the binary.

Q: What is a struct in Rust?
A: A struct is a custom data type that groups related fields. Example:
struct User { name: String, age: u32 }
Rust has three kinds: named-field structs, tuple structs, and unit structs.

Q: How do you implement methods on a struct?
A: Use an impl block:
impl User {
  fn greet(&self) -> String {
    format!("Hi, {}", self.name)
  }
}
The first parameter is typically &self, &mut self, or self.

Q: What is an enum in Rust?
A: An enum defines a type that can be one of several variants. Variants can hold data:
enum Shape {
  Circle(f64),
  Rectangle(f64, f64),
}
Enums are central to Rust's type system and pattern matching.

Q: What is pattern matching in Rust?
A: Pattern matching uses match to destructure and branch on values:
match shape {
  Shape::Circle(r) => ...,
  Shape::Rectangle(w, h) => ...,
}
The compiler ensures all variants are handled (exhaustiveness).

Q: What is the Option type in Rust?
A: Option<T> represents a value that may or may not exist:
enum Option<T> { Some(T), None }
It replaces null from other languages and forces you to explicitly handle the absence of a value.

Q: How do you safely extract a value from an Option?
A: Common methods include:
- unwrap() — panics if None
- unwrap_or(default) — returns default if None
- if let Some(v) = opt { ... } — pattern match
- match — exhaustive handling
- ? operator — propagates None

Q: What is the Result type in Rust?
A: Result<T, E> represents success or failure:
enum Result<T, E> { Ok(T), Err(E) }
It is the standard way to handle recoverable errors in Rust, used extensively in I/O and parsing.

Q: How does the ? operator work for error handling?
A: The ? operator placed after a Result or Option expression will:
- Return the inner value if Ok/Some
- Early-return the error/None to the caller if Err/None
It simplifies error propagation and reduces boilerplate.

Q: What is the difference between panic! and Result?
A: panic! is for unrecoverable errors — it unwinds the stack and crashes the thread.
Result is for recoverable errors — the caller decides how to handle the failure. Prefer Result in library code.

Q: What is a trait in Rust?
A: A trait defines a set of methods that a type must implement, similar to interfaces in other languages:
trait Summary {
  fn summarize(&self) -> String;
}
Traits enable polymorphism and generic programming.

Q: How do you implement a trait for a type?
A: Use impl Trait for Type:
impl Summary for Article {
  fn summarize(&self) -> String {
    format!("{}", self.title)
  }
}

Q: What are trait bounds in generics?
A: Trait bounds constrain generic types to those implementing specific traits:
fn print_summary<T: Summary>(item: &T)
Or using where syntax:
fn print_summary<T>(item: &T) where T: Summary

Q: What are some commonly derived traits in Rust?
A: Common derivable traits include:
- Debug — enables {:?} formatting
- Clone / Copy — value duplication
- PartialEq / Eq — equality comparison
- PartialOrd / Ord — ordering
- Hash — hashing support
Use #[derive(Debug, Clone)].

Q: What is the Copy trait vs the Clone trait?
A: Copy allows implicit bitwise copies on assignment (stack-only types like i32, bool).
Clone requires an explicit .clone() call and can perform deep copies. All Copy types must also implement Clone.

Q: What is a module in Rust?
A: Modules organize code into namespaces using mod:
mod network {
  pub fn connect() { }
}
Items are private by default; use pub to make them public. Modules can be in separate files.

Q: How does Rust's module file system work?
A: A module mod foo; tells the compiler to look for foo.rs or foo/mod.rs. Since Rust 2018, foo.rs with a sibling directory foo/ is preferred over foo/mod.rs.

Q: What is Cargo?
A: Cargo is Rust's build system and package manager. Key commands:
- cargo new — create a project
- cargo build — compile
- cargo run — compile and run
- cargo test — run tests
Dependencies are declared in Cargo.toml.

Q: What is a crate in Rust?
A: A crate is the smallest compilation unit. It can be a binary crate (with a main function) or a library crate. External crates are published on crates.io and added via Cargo.toml.

Q: What are iterators in Rust?
A: Iterators implement the Iterator trait, which requires a next() method returning Option<Item>. They are lazy — they do nothing until consumed by methods like collect(), sum(), or for loops.

Q: What are iterator adapters vs consumers?
A: Adapters transform iterators lazily (e.g., map(), filter(), take()).
Consumers drive iteration and produce a result (e.g., collect(), sum(), count(), for_each()).

Q: Give an example of chaining iterator methods.
A: let evens: Vec<i32> = (1..=10)
  .filter(|x| x % 2 == 0)
  .map(|x| x * x)
  .collect();
This filters even numbers 2–10, squares them, and collects into a Vec. Result: [4, 16, 36, 64, 100].

Q: What is a closure in Rust?
A: A closure is an anonymous function that can capture variables from its enclosing scope:
let add = |a, b| a + b;
Closures can capture by reference, mutable reference, or value (move).

Q: What are the Fn, FnMut, and FnOnce traits?
A: These traits describe how closures capture variables:
- Fn — captures by immutable reference
- FnMut — captures by mutable reference
- FnOnce — captures by value (can only be called once)
Every closure implements FnOnce; some also implement FnMut or Fn.

Q: What does the move keyword do with closures?
A: move forces the closure to take ownership of all captured variables:
let name = String::from("Rust");
let greet = move || println!("{}", name);
After this, name is no longer usable in the outer scope. Essential when sending closures to other threads.

Q: How do you create a new thread in Rust?
A: Use std::thread::spawn:
let handle = thread::spawn(|| {
  println!("Hello from thread!");
});
handle.join().unwrap();
Closures sent to threads typically need move to own their data.

Q: What is Send and Sync in Rust?
A: Send means a type can be transferred to another thread.
Sync means a type can be referenced from multiple threads (i.e., &T is Send).
Most types implement both automatically. Rc<T> is neither, while Arc<T> is both.

Q: What is Arc and Mutex for concurrency?
A: Arc<T> (Atomic Reference Counting) enables shared ownership across threads.
Mutex<T> provides interior mutability with locking.
Combined: Arc<Mutex<T>> allows multiple threads to safely read and write shared data.

Q: What are channels in Rust?
A: Channels provide message passing between threads via std::sync::mpsc (multiple producer, single consumer):
let (tx, rx) = mpsc::channel();
tx.send(42).unwrap();
let val = rx.recv().unwrap();

Q: What is unsafe Rust?
A: unsafe blocks let you perform operations the compiler cannot verify:
- Dereference raw pointers
- Call unsafe functions
- Access mutable statics
- Implement unsafe traits
- Access union fields
Use sparingly and document invariants.

Q: What are raw pointers in Rust?
A: Raw pointers *const T and *mut T are like C pointers — they can be null, dangling, or aliased. Creating them is safe, but dereferencing requires an unsafe block:
let p: *const i32 = &x;
unsafe { println!("{}", *p); }

Q: What is the String vs &str distinction?
A: String is an owned, heap-allocated, growable UTF-8 string.
&str is a borrowed string slice — a reference to UTF-8 data. String literals are &'static str. Use &str for function parameters when you only need to read.

Q: What is the Vec type?
A: Vec<T> is a growable, heap-allocated array. Create with:
let v = vec![1, 2, 3];
Key methods: push(), pop(), len(), iter(). It owns its elements and drops them when it goes out of scope.

Q: What is the HashMap type in Rust?
A: HashMap<K, V> stores key-value pairs with O(1) average lookup:
use std::collections::HashMap;
let mut map = HashMap::new();
map.insert("key", 42);
let val = map.get("key");
Keys must implement Eq and Hash.

Q: What is if let in Rust?
A: if let is a concise way to match a single pattern:
if let Some(val) = my_option {
  println!("{}", val);
}
It's syntactic sugar for a match with one arm and a wildcard. Use when you only care about one variant.

Q: What is while let in Rust?
A: while let loops as long as a pattern matches:
while let Some(val) = stack.pop() {
  println!("{}", val);
}
Useful for iterating until an Option returns None.

Q: What are generics in Rust?
A: Generics allow writing code that works with multiple types:
fn largest<T: PartialOrd>(list: &[T]) -> &T
The compiler performs monomorphization — generating specialized code for each concrete type used, so there is zero runtime cost.

Q: What is the Box smart pointer?
A: Box<T> allocates data on the heap and holds an owned pointer to it. Use cases:
- Types with unknown size at compile time (e.g., recursive types)
- Transferring ownership without copying large data
- Trait objects: Box<dyn Trait>

Q: What is dynamic dispatch with dyn Trait?
A: dyn Trait enables dynamic dispatch via a vtable (virtual method table):
fn draw(shape: &dyn Drawable)
Unlike generics (static dispatch), the concrete type is resolved at runtime. Trade-off: slight runtime cost, but allows heterogeneous collections.

Q: What is the From and Into trait?
A: From<T> defines how to create a type from another:
impl From<&str> for String
Into<T> is the reciprocal — implementing From automatically provides Into. Widely used for ergonomic type conversions and error handling.

Q: What is the Display trait?
A: std::fmt::Display enables user-facing string formatting with {}:
impl fmt::Display for Point {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "({}, {})", self.x, self.y)
  }
}
Unlike Debug, it cannot be derived automatically.

Q: How do you write unit tests in Rust?
A: Place tests in the same file with a #[cfg(test)] module:
#[cfg(test)]
mod tests {
  use super::*;
  #[test]
  fn it_works() {
    assert_eq!(2 + 2, 4);
  }
}
Run with cargo test.

Q: What is the difference between Rc and Arc?
A: Both are reference-counted smart pointers for shared ownership.
Rc<T> — single-threaded only, uses non-atomic counter (faster).
Arc<T> — thread-safe, uses atomic counter (slight overhead).
Use Arc when sharing data across threads; Rc otherwise.