Title: Rust Ownership And Borrowing Explained — LearnCoachAssist

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

Q: What happens to a value when its owner goes out of scope in Rust?
A: It is dropped — its drop function runs and its memory is freed.

Q: Which standard library function is called when a value goes out of scope?
A: drop, from the Drop trait, is called automatically at the end of the variable's scope.

Q: What is a "move" in Rust?
A: A transfer of ownership: assigning a value to another variable or passing it to a function moves the value, invalidating the source binding.

Q: Why does Rust move ownership instead of shallow-copying by default?
A: Moving avoids double-free bugs and keeps the type system simple — for stack-allocated types that own heap data (like String), copying the pointer would leave two owners.

Q: After let s1 = String::from("hi"); let s2 = s1;, can s1 still be used?
A: No. s1 is invalidated by the move; using it is a compile-time error.

Q: Which traits enable copy-by-value rather than moving?
A: Copy and Clone. Types implementing Copy (e.g. integers, bool, char, tuples of Copy types) are copied on assignment; Clone is an explicit .clone() method.

Q: What is the difference between Copy and Clone?
A: Copy is an implicit, bitwise copy marker with no custom behavior; Clone is an explicit method (.clone()) that may perform arbitrary, potentially expensive duplication.

Q: Can a type be Copy if it also implements Drop?
A: No. The compiler rejects types that implement both Copy and Drop, because Copy implies no special cleanup is needed.

Q: What does the Copy trait inherit from?
A: Copy is a marker trait (a unit trait) that requires implementing Clone.

Q: What is a reference in Rust?
A: A reference (&T for shared, &mut T for mutable) is a non-owning pointer to a value, governed by the borrow checker.

Q: What is borrowing?
A: Borrowing is the act of passing a reference to a value rather than transferring ownership, so the original owner retains it.

Q: How many mutable references to a value can exist at one time?
A: Exactly one. Two mutable references to the same data in the same scope are a compile-time error.

Q: How many immutable references to a value can exist at one time?
A: Any number, but they cannot coexist with a mutable reference to the same value in the same scope.

Q: Can you have a mutable and an immutable reference to the same value at the same time?
A: No. While a mutable reference exists, no immutable references may exist (and vice versa) for the same data in the same scope.

Q: What is a "non-lexical lifetime" (NLL)?
A: A borrow-checker refinement where a reference's lifetime ends at its last use, not at the end of its enclosing block, allowing more code to compile.

Q: What is a dangling reference?
A: A reference that points to memory that has been freed or to a value that has gone out of scope; Rust's borrow checker prevents them at compile time.

Q: Does Rust allow dangling references?
A: No. The compiler guarantees references always point to valid data — code that would create a dangling reference fails to compile.

Q: What are lifetime annotations?
A: Generic parameters (e.g. 'a) on references that tell the compiler how multiple references relate in time.

Q: What is the elision rule for lifetimes in function signatures?
A: Each input reference gets its own lifetime, and if there is exactly one input reference, its lifetime is assigned to all output references.

Q: What does the lifetime annotation &'a i32 mean?
A: A reference to an i32 that lives at least as long as the lifetime 'a.

Q: What is the "static lifetime 'static"?
A: A lifetime that lasts for the entire duration of the program. String literals are &'static str.

Q: What is a lifetime parameter on a struct?
A: A generic parameter like struct Ref<'a> { r: &'a i32 } that says the struct cannot outlive the data it borrows.

Q: What is a slice?
A: A reference to a contiguous sequence of elements plus a length — written &[T] (shared) or &mut [T] (mutable) — that always borrows data.

Q: What does [..], [a..], [..b], and [a..b] mean for ranges?
A: Full slice; from a to end; from start to b (exclusive); elements a to b (exclusive).

Q: What is the type of a string literal like "hello"?
A: &'static str — an immutable reference to a string slice with 'static lifetime.

Q: How do you create a String from a string literal?
A: String::from("hello") or "hello".to_string().

Q: What is the difference between String and &str?
A: String is an owned, growable, heap-allocated UTF-8 string; &str is an immutable borrowed view (slice) into UTF-8 data.

Q: How do you obtain a &str from a String?
A: Use the deref coercion &s where s: String, or call &s[..], or s.as_str().

Q: Can you mutate through a &str?
A: No. &str is a shared (immutable) reference. You need String or &mut str to mutate.

Q: What does the Deref trait do?
A: It allows a type to be dereferenced with * and enables implicit coercion from &T to &U when T: Deref<Target = U>.

Q: What is deref coercion?
A: An automatic coercion that converts a reference to a type that implements Deref into a reference to the type it derefs to (e.g. &String to &str).

Q: How does Box<T> interact with ownership?
A: A Box<T> is a smart pointer that owns a heap-allocated T; when the box is dropped, the inner T is dropped.

Q: What happens when a Box<T> is moved?
A: Ownership of the heap allocation transfers to the new owner; the original Box binding is invalidated.

Q: What is the Drop trait?
A: A trait with a single method fn drop(&mut self) that runs custom cleanup code when a value goes out of scope.

Q: Is drop called automatically?
A: Yes. drop is invoked automatically at the end of a value's scope, in reverse order of declaration.

Q: How do you explicitly drop a value before the end of its scope?
A: Call std::mem::drop(value). You cannot call value.drop() directly because Drop::drop takes &mut self and would still leave the binding valid.

Q: Why is std::mem::drop a function and not a method?
A: Taking ownership in drop(value) guarantees the value is dropped at the end of the drop function call, making the pattern safe and explicit.

Q: What is the stack vs the heap in Rust memory?
A: Stack holds fixed-size values with known lifetimes (LIFO); heap holds values whose size or lifetime is dynamic and is managed via allocation and pointers.

Q: Which Rust types are stored entirely on the stack?
A: Types with a known fixed size and no heap-allocated contents, like i32, (i32, i32), arrays of Copy types, and structs containing only such fields.

Q: Where is a String's actual character data stored?
A: On the heap. The String struct itself (pointer, length, capacity) lives on the stack, and the buffer it points to is on the heap.

Q: What is RAII in Rust?
A: Resource Acquisition Is Initialization: resources are tied to object lifetimes, and a type's Drop implementation releases them when the value goes out of scope.

Q: What is a "double free" and does Rust allow it?
A: A double free is freeing the same memory twice; Rust's ownership model guarantees this cannot happen, because only one owner can drop a value.

Q: What is a use-after-free, and does Rust allow it?
A: Accessing memory after it has been freed; the borrow checker prevents this at compile time by ensuring references never outlive their referent.

Q: What does clone() do?
A: Creates a deep copy of the value, producing a new, independent owner; it requires the Clone trait.

Q: When should you use clone()?
A: When you genuinely need an independent copy of owned data — typically when multiple owners are required, not as a default escape hatch from the borrow checker.

Q: What is the Clone trait's signature?
A: pub trait Clone { fn clone(&self) -> Self; } — it takes a shared reference and returns an owned value.

Q: What is the "interior mutability" pattern?
A: Types like Cell<T> and RefCell<T> allow mutation through a shared reference, with the mutability rules enforced at runtime instead of compile time.

Q: What does RefCell<T> do?
A: It enforces Rust's aliasing rules at runtime via reference counts: at most one mutable borrow OR many shared borrows at a time; violations cause a panic!.

Q: What does Cell<T> do?
A: It enables interior mutability for Copy types by replacing the value in place (cell.set(x)), avoiding the need for mutable references.

Q: What is the difference between Cell and RefCell?
A: Cell<T> works only for Copy types and has no runtime borrow tracking; RefCell<T> works for any T but tracks borrows at runtime and can panic.

Q: What is Mutex<T>?
A: A thread-safe interior-mutability primitive providing exclusive (mutating) access to T; locking returns a MutexGuard that acts as a smart pointer.

Q: What is RwLock<T>?
A: A reader-writer lock: many concurrent shared readers OR one exclusive writer, with runtime enforcement.

Q: What is the Send marker trait?
A: Indicates that ownership of a value can be transferred safely between threads.

Q: What is the Sync marker trait?
A: Indicates that a value can be safely shared between threads via &T; it is automatically implemented if &T is Send.

Q: Are Send and Sync auto-implemented?
A: They are auto-implemented by the compiler for types whose components are all Send/Sync; you can also implement them manually with unsafe.

Q: What does the borrow checker check?
A: That all references obey the rules: only one mutable reference (or any number of immutable) at a time, and references always point to valid data.

Q: At what point does the borrow checker run?
A: At compile time, on every Rust program; it is the core of Rust's memory safety guarantees without a garbage collector.

Q: What is a "scope" in Rust?
A: A block of code delimited by { }; variables declared inside it are dropped at the closing brace.

Q: Does match create a new scope?
A: Yes. Each match arm body is a new scope; bindings introduced inside it are dropped at the end of the arm.

Q: What is "shadowing" in Rust?
A: Redeclaring a variable with the same name in the same scope using let; the new binding shadows the old until the new one goes out of scope or is shadowed again.

Q: Does shadowing move or drop the old variable?
A: No. The old variable's value is still valid until its own scope ends; shadowing simply makes the name refer to a new value.

Q: Can shadowing change a variable's type?
A: Yes. Unlike mutation, shadowing can rebind a name to a value of a different type.

Q: What is the difference between mutation and shadowing?
A: Mutation (let mut x) changes the value in place while keeping the type and binding; shadowing rebinds the name, possibly to a new type or value.

Q: What is the Copy semantics for tuple of references like &(i32, i32)?
A: References are Copy, so the tuple is Copy; assignment copies the reference, not the pointed-to data.

Q: How does ownership work with function return values?
A: Returning a value transfers ownership to the caller; the caller becomes the new owner and is responsible for dropping it.

Q: How do you give ownership back from a function without moving?
A: Return the value (moves it to the caller) or return a reference whose lifetime is tied to an input or to 'static.

Q: What is a "mutable reference cycle" and can Rust cause memory leaks from it?
A: A cycle of references (e.g. via Rc<RefCell<T>>) where items keep each other alive; Rust's compile-time rules cannot prevent these, so they can leak.

Q: What is Rc<T>?
A: A reference-counted smart pointer for single-threaded shared ownership; clone increments the count, drop decrements it, and the inner value is freed at zero.

Q: What is Arc<T>?
A: An atomically reference-counted smart pointer for shared ownership across threads; same API as Rc but uses atomic operations.

Q: What is the difference between Rc and Arc?
A: Rc is not Send/Sync and is faster (non-atomic counts); Arc is thread-safe but slightly slower due to atomic operations.

Q: What is Weak<T>?
A: A non-owning reference counted alongside Rc/Arc that does not keep the value alive; upgraded via upgrade() returning Option<Rc<T>>.

Q: What is Cow<'a, T>?
A: A clone-on-write enum Borrowed(&'a T) | Owned(<T as ToOwned>::Owned) that avoids cloning when a borrowed value is sufficient.

Q: What does the Ref type represent?
A: A guard returned by RefCell::borrow() that acts as a shared reference to the inner data and releases the borrow on drop.

Q: What does the RefMut type represent?
A: A guard returned by RefCell::borrow_mut() that acts as a mutable reference to the inner data, releasing the borrow on drop.

Q: What is a "lifetime bound" in a generic?
A: A constraint like T: 'a meaning all references in T must outlive the lifetime 'a.

Q: What does the syntax struct Parser<'a> { input: &'a str } declare?
A: That the Parser borrows a string slice that must live at least as long as the Parser itself.

Q: What is lifetime subtyping?
A: When 'a: 'b (lifetime 'a outlives 'b), references with 'a can be used where references with 'b are expected.

Q: What is a "higher-ranked trait bound" (HRTB)?
A: The syntax for<'a> F: Fn(&'a T) -> &'a T, expressing that a bound must hold for every possible lifetime.

Q: What is the orphan rule?
A: You can implement a foreign trait for a foreign type only if at least one of the trait or type is local to your crate.

Q: What is the variance of &T with respect to T?
A: &T is covariant in T: if 'a outlives 'b, then &'a T can be used wherever &'b T is expected for the lifetime, and &T is covariant in the lifetime too.

Q: What is the variance of &mut T with respect to T?
A: &mut T is invariant in T: you cannot substitute a subtype or supertype because the mutability gives write access.

Q: What is the variance of *const T and *mut T?
A: *const T is covariant in T; *mut T is invariant in T.

Q: What does "invariant" mean for type parameters?
A: Neither covariant nor contravariant: no implicit subtype substitution is allowed in that position.

Q: What is PhantomData<T>?
A: A zero-sized marker that tells the compiler a type acts as if it owns or borrows a T, for variance, drop check, and auto-trait purposes.

Q: Why is PhantomData used in smart-pointer-like types?
A: To control variance and to ensure the borrow/drop checker considers the inner T even though it is not stored directly.

Q: What is the "drop check" in Rust?
A: A compile-time analysis that ensures generic types cannot outlive values they may need to drop; PhantomData participates in this check.

Q: Why does Rust forbid returning a reference to a local variable?
A: Because the local is dropped at the end of the function, leaving a dangling reference; the borrow checker rejects it at compile time.

Q: What is the "aliasing XOR mutability" rule of Rust references?
A: At any program point, a value is either accessed via any number of shared (&) references or via exactly one mutable (&mut) reference — never both.

Q: Why is this rule fundamental to Rust's safety?
A: It prevents data races at compile time and underpins the correctness of compiler optimizations like the LLVM noalias attribute used on &mut T.

Q: What is a "data race" and can safe Rust produce one?
A: A data race is concurrent unsynchronized access where at least one is a write; safe Rust's type system prevents data races because &mut T is Send only when the type is Send and shared access requires Sync.

Q: What does "NLL" stand for and when was it stabilized?
A: Non-Lexical Lifetimes, stabilized in Rust 1.31 (December 2018).

Q: What is "Polonius" in the context of the borrow checker?
A: An experimental, more precise borrow checker that computes loan lifetimes with a dataflow analysis; it can accept more code than the current NLL implementation in some cases.

Q: What is a "PhantomData<fn(T) -> T>" trick used for?
A: To make a type covariant in T only (not contravariant), or to indicate a function-like relationship; PhantomData<T> makes a type own or borrow T with default variance.

Q: What is "auto-deref" when calling methods?
A: Method resolution repeatedly dereferences the receiver with Deref until a method is found, so s.len() works for s: String via Deref<Target = str>.

Q: Why can you call .len() on both String and &str?
A: Because of auto-deref and Deref coercion: &String coerces to &str, which implements methods like len.

Q: What is "ownership of an array literal [1, 2, 3]"?
A: It is an array of Copy elements, so the array itself is Copy and is duplicated on assignment without moving.

Q: Why can't you have [String; 3] as Copy?
A: Because String is not Copy, and arrays are Copy only if all their elements are Copy.

Q: What is "ownership of an enum variant"?
A: An enum owns exactly the data of one of its variants; moving the enum moves the data of that variant.

Q: Why can a match on an enum move out of one variant but not the other?
A: Because the compiler ties the binding to the specific variant in the arm; if a variant binds by value, the inner data is moved into that binding.

Q: What does the #[may_dangle] attribute on Drop mean?
A: It declares that the drop implementation does not access any data of the type's generic parameters during drop, allowing the drop check to be relaxed.

Q: When is #[may_dangle] typically used?
A: In intrusive collections and low-level smart pointers (e.g. linked-list implementations) that must drop even when their owned references are no longer valid.

Q: What is the difference between v.iter() and v.into_iter()?
A: v.iter() yields &T (immutable borrow of each element); v.into_iter() consumes the collection and yields T (owned).

Q: What does v.iter_mut() yield?
A: &mut T for each element, allowing in-place mutation; the vector is mutably borrowed for the iteration.

Q: What is "partial move" in Rust?
A: When a struct field is moved out while the rest is borrowed or partially used; subsequent use of the moved field is forbidden, and the parent binding becomes partially moved.

Q: Why does destructuring a struct move its fields?
A: Because pattern bindings in let or match move out by default; prefix the field with ref or & to borrow it.

Q: What does ref do in a pattern?
A: It binds the matched value by reference, e.g. let Foo { ref x } = f; gives x: &T instead of moving x out of f.

Q: What does ref mut do in a pattern?
A: It binds the matched value by mutable reference, e.g. let Foo { ref mut x } = f; gives x: &mut T.

Q: What is "match ergonomics" introduced in Rust 1.26?
A: When matching a reference, bindings in the pattern automatically become references, so you don't have to write ref explicitly.

Q: What is a "destructuring assignment" like let (a, b) = tuple;?
A: A pattern that moves (or copies) fields from a compound value into individual bindings.

Q: How does for loop ownership work?
A: for x in collection uses into_iter() by default, consuming the collection; use iter() or iter_mut() to iterate by reference.

Q: What is the difference between &Vec<T> and &[T] as function parameters?
A: &Vec<T> requires a specific type; &[T] is more flexible — it accepts vectors, arrays, and slices thanks to deref/unsized coercion.

Q: What is "deref coercion" in function arguments?
A: When a function takes &[T], you can pass &Vec<T> and it coerces automatically via Vec<T>: Deref<Target = [T]>.

Q: What is unsized coercion?
A: An implicit coercion from a sized type to an unsized (DST) type, e.g. &Vec<T> to &[T], by "forgetting" the size information.

Q: What is a dynamically sized type (DST)?
A: A type whose size is not known at compile time, such as [T] and str; DSTs can only be used behind a pointer like &[T] or Box<[T]>.

Q: What is the Sized trait?
A: An auto trait that is implemented for types whose size is known at compile time; generic type parameters have an implicit T: Sized bound.

Q: How do you opt out of the Sized bound?
A: Write T: ?Sized as a trait bound, allowing the parameter to be a DST like str or [T].

Q: What is "partial move" in a struct pattern?
A: When you destructure a struct and move out some fields while leaving others, the whole struct becomes partially moved; the moved fields can be used, but accessing the unmoved parts through the original binding is forbidden.

Q: Why is "ownership of the iterator returned by vec.iter()" tied to the borrow?
A: Because the iterator's lifetime parameter is tied to the borrow of the vector; the iterator cannot outlive the vector's borrow.

Q: What is Pin<P> used for?
A: To pin a value at a stable memory address so it cannot be moved, enabling safe self-referential data structures and async state machines.