🦀

Rust MCQ

Test your Rust knowledge with 100 multiple choice questions covering fundamentals to advanced concepts, with instant feedback and explanations.

100 Questions 40 Beginner 40 Intermediate 20 Advanced

How This Practice Test Works

Every question below expands right on this page — click a question to reveal its four options, pick the one you think is correct, and you'll get instant feedback along with the correct answer and a short explanation of the reasoning. Questions are grouped by difficulty, so start with the 40 beginner questions to confirm your fundamentals, work through the 40 intermediate ones, and finish with the 20 advanced questions that mirror what exams and technical screenings actually ask. There's no sign-up, no timer, and no limit — retake the test as often as you like.

Curated by Tech Baithak Editorial Team  ·  Last updated: June 2026

1

Which organization develops the Rust programming language?

B

Correct Answer

Mozilla (now the Rust Foundation)

Explanation

Rust was created by Graydon Hoare at Mozilla in 2006. The Rust Foundation was established in 2021 to steward the project.

2

What is Rust's primary memory safety guarantee?

B

Correct Answer

Ownership and borrowing rules enforced at compile time, eliminating dangling pointers and data races without a GC

Explanation

Rust's ownership system ensures memory safety at compile time with no runtime garbage collector. The borrow checker prevents use-after-free and data races.

3

What is ownership in Rust?

B

Correct Answer

A set of rules governing when memory is allocated and freed: each value has exactly one owner; the value is dropped when the owner goes out of scope

Explanation

Rust's ownership model: each value has one owner. When the owner goes out of scope, the value is dropped (memory freed). Ownership can be moved but not copied by default.

4

What is a move in Rust?

B

Correct Answer

Transferring ownership of a value to another variable, making the original variable invalid

Explanation

let s1 = String::from("hello"); let s2 = s1; — s1 is moved into s2. Using s1 after this is a compile error.

5

What is the Copy trait?

B

Correct Answer

A marker trait for types that can be bitwise-copied on assignment, so the original remains valid

Explanation

Types like i32, bool, char, and tuples of Copy types implement Copy. let x = 5; let y = x; — x is still valid because integers are Copy.

6

What is a reference in Rust?

B

Correct Answer

A pointer to a value that does not own the data, allowing access without taking ownership

Explanation

&T is an immutable reference; &mut T is a mutable reference. References are guaranteed to be valid (non-dangling) by the borrow checker.

7

What is borrowing in Rust?

B

Correct Answer

Creating a reference to a value without taking ownership

Explanation

fn print(s: &String) borrows s without taking ownership. The original owner retains ownership after the function returns.

8

What are Rust's borrowing rules?

B

Correct Answer

Either one mutable reference OR any number of immutable references — never both at the same time

Explanation

The borrow checker enforces: at most one &mut T, or any number of &T at a time. This prevents data races at compile time.

9

What is a slice in Rust?

B

Correct Answer

A reference to a contiguous subsequence of elements in a collection

Explanation

&str is a string slice; &[i32] is an integer slice. Slices hold a pointer and a length without owning the data.

10

What is the difference between &str and String?

B

Correct Answer

&str is a borrowed reference to string data (string slice); String is an owned, heap-allocated, growable string

Explanation

&str is a view into string data (can point to a String or string literal). String owns its data and can grow. Use &str for function parameters accepting both.

11

What is an enum in Rust?

B

Correct Answer

A type that can be one of several variants, each optionally holding data

Explanation

enum Message { Quit, Move { x: i32, y: i32 }, Write(String) } — Rust enums are algebraic data types, far more powerful than C enums.

12

What is Option<T> used for?

B

Correct Answer

Representing a value that may or may not exist: Some(T) or None

Explanation

Option<T> replaces null pointers. You must handle both Some(x) and None, preventing null pointer dereferences.

13

What is Result<T, E>?

B

Correct Answer

A type representing either success Ok(T) or failure Err(E)

Explanation

Result is used for operations that can fail: fn open(path: &str) -> Result<File, io::Error>. Callers must handle both Ok and Err cases.

14

What does the ? operator do in Rust?

B

Correct Answer

Unwraps a Result, returning early with Err if the operation failed

Explanation

let file = File::open("path")?; returns the Err to the caller if it fails, otherwise unwraps the Ok value. Replaces verbose match expressions.

15

What is a struct in Rust?

B

Correct Answer

A custom data type grouping related named fields

Explanation

struct Point { x: f64, y: f64 } defines a named group of values. Structs are value types stored on the stack unless boxed.

16

What is a trait in Rust?

B

Correct Answer

A collection of methods that types can implement to share behavior

Explanation

Traits (like Java interfaces or Haskell typeclasses) define shared behavior. trait Area { fn area(&self) -> f64; } implemented by Circle, Rectangle, etc.

17

What is a lifetime in Rust?

B

Correct Answer

An annotation describing how long a reference is valid, ensuring references do not outlive the data they point to

Explanation

Lifetime annotations ('a) on references let the compiler verify references don't outlive their data: fn longest<'a>(x: &'a str, y: &'a str) -> &'a str.

18

What is the borrow checker?

B

Correct Answer

A compile-time analysis that enforces ownership and borrowing rules to prevent use-after-free, dangling references, and data races

Explanation

The borrow checker is part of the Rust compiler. It checks that references are valid and that mutability rules are respected — all at compile time.

19

What is pattern matching in Rust?

B

Correct Answer

The match expression that destructures and matches against patterns like enum variants, literals, tuples, and structs

Explanation

match coin { Coin::Penny => 1, Coin::Nickel => 5, _ => 0 } is exhaustive — all cases must be handled.

20

What does panic! do?

B

Correct Answer

Terminates the current thread with an error message (optionally unwinds the stack)

Explanation

panic!("message") crashes the program (or thread). It's for unrecoverable errors. Use Result for recoverable errors.

21

What is Box<T>?

B

Correct Answer

A heap-allocated smart pointer providing unique ownership of a value

Explanation

Box<T> puts T on the heap. Use Box when you need a heap allocation, a trait object (Box<dyn Trait>), or a recursive data type.

22

What is Rc<T>?

B

Correct Answer

Reference-counted smart pointer enabling multiple owners of the same heap data in single-threaded contexts

Explanation

Rc<T> (Reference Counted) allows multiple owners. The data is freed when the last Rc is dropped. Not Send/Sync — use Arc for multithreading.

23

What is Arc<T>?

B

Correct Answer

An Atomically Reference Counted smart pointer safe for sharing across threads

Explanation

Arc<T> is the thread-safe version of Rc<T>, using atomic operations for the reference count. Use with Mutex<T> for shared mutable state across threads.

24

What is Cell<T> and RefCell<T>?

B

Correct Answer

Types providing interior mutability: Cell<T> for Copy types, RefCell<T> for runtime-checked borrows

Explanation

Interior mutability allows mutation through an immutable reference. RefCell<T> enforces borrow rules at runtime, panicking on violations.

25

What is the use keyword in Rust?

B

Correct Answer

Brings a path into scope to avoid repeating long module paths

Explanation

use std::collections::HashMap; allows using HashMap directly instead of the full path.

26

What is cargo in Rust?

B

Correct Answer

Rust's package manager and build system

Explanation

Cargo handles dependencies (Cargo.toml), building (cargo build), testing (cargo test), documentation (cargo doc), and publishing to crates.io.

27

What is a crate in Rust?

B

Correct Answer

The smallest unit of compilation — a binary or library package

Explanation

A crate is a binary (has main) or a library. crates.io is the package registry. Cargo.toml specifies crate dependencies.

28

What does the derive attribute do?

B

Correct Answer

Automatically implements specified traits (Debug, Clone, PartialEq, etc.) for a type using procedural macros

Explanation

#[derive(Debug, Clone, PartialEq)] auto-generates the implementations of those traits for the struct or enum.

29

What is the println! macro?

B

Correct Answer

A macro that formats and prints a string followed by a newline to stdout

Explanation

println!("Value: {}", x) formats and prints to stdout with a newline. {} uses the Display trait; {:?} uses the Debug trait.

30

What is a vector Vec<T> in Rust?

B

Correct Answer

A heap-allocated, growable, type-safe array

Explanation

Vec<T> grows dynamically. vec![1,2,3] or Vec::new() with push(). Elements are stored contiguously on the heap.

31

What is an iterator in Rust?

B

Correct Answer

A trait (Iterator) with a next() method, enabling lazy consumption of sequences with adaptors like map, filter, and collect

Explanation

v.iter().filter(|x| *x > 2).map(|x| x * 2).collect::<Vec<_>>() chains lazy iterator adaptors, executing only on collect().

32

What is the difference between iter(), iter_mut(), and into_iter()?

B

Correct Answer

iter() yields &T; iter_mut() yields &mut T; into_iter() consumes the collection yielding T

Explanation

Use iter() for read-only access, iter_mut() for mutation, into_iter() when you want to consume and transform the collection.

33

What is the Drop trait?

B

Correct Answer

A trait with fn drop(&mut self) called automatically when a value goes out of scope, for custom cleanup

Explanation

impl Drop for MyResource { fn drop(&mut self) { /* cleanup */ } } runs when the value goes out of scope, implementing RAII.

34

What is an impl block?

B

Correct Answer

A block defining methods and associated functions for a struct or enum

Explanation

impl Point { fn new(x: f64, y: f64) -> Self { ... } fn distance(&self) -> f64 { ... } } defines methods on Point.

35

What is a closure in Rust?

B

Correct Answer

An anonymous function that captures variables from its environment using |params| expression syntax

Explanation

let double = |x| x * 2; captures no environment. Closures can capture by reference (&), mutable reference (&mut), or by value (move).

36

What is the Fn, FnMut, FnOnce trait hierarchy?

B

Correct Answer

FnOnce consumes captured vars (called once); FnMut mutates them (called repeatedly); Fn only borrows (called any number of times)

Explanation

FnOnce ⊇ FnMut ⊇ Fn. A function accepting Fn can be passed any closure. Closures implement the most specific trait based on how they capture.

37

What does the move keyword do in a closure?

B

Correct Answer

Forces the closure to take ownership of all captured variables rather than borrowing them

Explanation

move || { use_data(data) } moves data into the closure. Required when passing closures to threads where the outer scope may not outlive the thread.

38

What are generics in Rust?

B

Correct Answer

Type parameters (<T>) that allow writing functions, structs, and enums that work with multiple types while maintaining type safety

Explanation

fn largest<T: PartialOrd>(list: &[T]) -> T works for any type T that implements PartialOrd. Rust monomorphizes generics at compile time.

39

What is monomorphization?

B

Correct Answer

The compiler generating concrete implementations of generic code for each concrete type used

Explanation

When you use Vec<i32> and Vec<String>, Rust compiles two separate Vec implementations. This makes generics zero-cost but can increase binary size.

40

What is a Rust lifetime elision rule?

B

Correct Answer

Compiler rules that infer lifetime annotations in common patterns so they don't need to be written explicitly

Explanation

Three elision rules: (1) each input ref gets its own lifetime; (2) one input → output gets same; (3) self method → output gets self's lifetime.

1

What is a trait object (dyn Trait)?

B

Correct Answer

A runtime-dispatched reference to any type implementing a trait, enabling dynamic polymorphism via a vtable

Explanation

Box<dyn Animal> or &dyn Animal is a fat pointer (data ptr + vtable ptr) that can hold any Animal implementor. Use when concrete types aren't known at compile time.

2

What is the difference between static dispatch (generics) and dynamic dispatch (dyn Trait)?

B

Correct Answer

Static dispatch inlines/monomorphizes for each concrete type (faster); dynamic dispatch uses vtable (slower but smaller binary, enables heterogeneous collections)

Explanation

fn f<T: Display>(x: T) is statically dispatched. fn g(x: &dyn Display) is dynamically dispatched via vtable indirection.

3

What is the Send trait?

B

Correct Answer

A marker trait indicating ownership of the type can be transferred across thread boundaries

Explanation

Types are Send if sending them to another thread is safe. Most types are Send. Rc<T> is not Send (non-atomic reference counting).

4

What is the Sync trait?

B

Correct Answer

A marker trait indicating it is safe for multiple threads to hold shared references (&T) to the type simultaneously

Explanation

T: Sync means &T: Send. Mutex<T> is Sync even if T is not, because it serializes access.

5

What is the Mutex<T> in Rust?

B

Correct Answer

A mutual exclusion primitive that provides safe mutable access to T across threads, returning a MutexGuard when locked

Explanation

let data = Arc::new(Mutex::new(5)); let guard = data.lock().unwrap(); *guard += 1; — the guard releases the lock when dropped.

6

What is async/await in Rust?

B

Correct Answer

A zero-cost asynchronous programming model where async functions return futures, driven by an executor (tokio, async-std)

Explanation

async fn fetch() -> Result<...> { let resp = client.get(url).await?; } Futures are lazy state machines. Executors like tokio::main drive them.

7

What is a Future in Rust?

B

Correct Answer

A lazy computation represented as a state machine that produces a value when polled to completion

Explanation

Futures implement trait Future { type Output; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>; }. They do nothing until polled by an executor.

8

What is unsafe Rust?

B

Correct Answer

Code in an unsafe block that opts out of some borrow checker guarantees, enabling raw pointer dereference, calling unsafe functions, etc.

Explanation

unsafe { *raw_ptr } allows raw pointer dereference. Use unsafe for FFI, performance-critical code, and implementing safe abstractions. The programmer assumes correctness.

9

What is a raw pointer in Rust?

B

Correct Answer

*const T or *mut T — pointers without lifetime or aliasing guarantees, usable only in unsafe blocks

Explanation

Raw pointers (*const T) don't guarantee non-null or valid memory. Creating them is safe; dereferencing requires unsafe.

10

What is the From/Into trait?

B

Correct Answer

Conversion traits: From<T> for infallible conversions; Into<T> is the reciprocal (implementing From auto-implements Into)

Explanation

impl From<i32> for MyType { fn from(x: i32) -> Self { ... } } then i32::from(x) or x.into() both work.

11

What is the Display trait?

B

Correct Answer

A trait requiring fmt::Display implementation, enabling {} formatting with println!

Explanation

impl fmt::Display for Point { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "({},{})", self.x, self.y) } }

12

What is a macro in Rust?

B

Correct Answer

Code that generates code during compilation — declarative macros (macro_rules!) or procedural macros (#[derive], attribute, function-like)

Explanation

Macros avoid code duplication. macro_rules! my_macro { ... } is declarative. proc macros (like serde's #[derive(Serialize)]) use the Rust compiler API.

13

What is the newtype pattern?

A

Correct Answer

Using a tuple struct of one field to create a distinct named type for type safety

Explanation

struct Meters(f64); and struct Kilograms(f64) are distinct types despite holding f64. Prevents accidental mixing of units while having zero runtime cost.

14

What is the purpose of PhantomData<T>?

B

Correct Answer

A zero-sized type used to make the type system aware of an unused generic parameter for lifetime or type variance purposes

Explanation

struct Iter<'a, T> { ptr: *const T, _phantom: PhantomData<&'a T> } tells the compiler the Iter borrows T with lifetime 'a, enabling proper variance.

15

What is Pin<T> used for?

B

Correct Answer

Preventing a value from being moved in memory, required for self-referential structs and async futures

Explanation

Pin<P> guarantees the pointee won't be moved after pinning. Async/await creates self-referential state machines that would be invalidated by moves, so futures require Pin.

16

What is the Deref coercion?

B

Correct Answer

Implicit conversion when passing a &T where &U is expected, if T implements Deref<Target=U>

Explanation

Box<String> coerces to &String which coerces to &str. String::from("hello") can be passed as &str. This chain is performed automatically.

17

What is the difference between clone() and copy?

B

Correct Answer

Copy is an implicit bitwise copy for simple types; clone() is an explicit deep copy for complex types like String

Explanation

Integers implement Copy — assignment copies automatically. String does not implement Copy; you must call .clone() to create a deep copy.

18

What is a type alias (type) in Rust?

B

Correct Answer

An alternate name for an existing type with no additional safety guarantees: type Result<T> = Result<T, io::Error>

Explanation

type Thunk = Box<dyn Fn() + Send + 'static>; is a type alias. Unlike struct Newtype(T), a type alias IS the same type.

19

What is the ? Sized bound?

B

Correct Answer

Relaxing the default Sized constraint on a generic parameter to allow dynamically-sized types (DSTs) like str and [T]

Explanation

fn f<T: ?Sized>(x: &T) allows passing str and [T] as well as Sized types. fn f<T>(x: &T) implicitly requires T: Sized.

20

What is Rust's impl Trait syntax in function arguments?

B

Correct Answer

Shorthand for a generic type parameter constrained by a trait: fn f(x: impl Display) is equivalent to fn f<T: Display>(x: T)

Explanation

fn double_and_print(x: impl Display + Debug) is cleaner than generics for simple cases. It's static dispatch — the compiler generates a concrete implementation.

21

What is the purpose of Cow<'a, B> (Clone on Write)?

B

Correct Answer

A smart pointer holding either a borrowed reference or an owned value, only cloning when mutation is needed

Explanation

Cow::Borrowed(&str) avoids allocation; Cow::Owned(String) owns data. Cow::to_mut() clones only when mutation is needed. Useful for APIs accepting both &str and String.

22

What is the BufReader and BufWriter purpose in Rust?

B

Correct Answer

Wrappers adding buffering to any Reader/Writer, reducing the number of system calls for small reads/writes

Explanation

BufReader<R> buffers reads from R into a 8KB buffer by default. Instead of one syscall per byte, you get one syscall per 8KB. Use flush() on BufWriter before dropping.

23

What is Rust's type inference limitations?

B

Correct Answer

Rust cannot infer type parameters that don't appear in method arguments; use turbofish ::<> syntax or annotate the variable

Explanation

let v = Vec::new() fails (can't infer T). let v: Vec<i32> = Vec::new() or Vec::<i32>::new() works. Iterator collect() often needs type annotation.

24

What is the turbofish operator ::<> in Rust?

B

Correct Answer

Syntax for specifying generic type parameters explicitly at the call site when inference fails: "hello".parse::<i32>()

Explanation

"42".parse::<i32>().unwrap() or Vec::<i32>::new() uses turbofish when the compiler can't infer the type from context.

25

What is Rust's RwLock<T>?

B

Correct Answer

A synchronization primitive allowing multiple concurrent readers or one exclusive writer

Explanation

RwLock.read() can be held by many threads simultaneously. RwLock.write() requires exclusive access. Use when reads are frequent and writes are rare.

26

What are proc macros in Rust?

B

Correct Answer

Macros implemented as Rust functions that operate on token streams, enabling powerful code generation like #[derive(Serialize)]

Explanation

Procedural macros are separate crates (proc-macro = true) that receive TokenStream and return TokenStream. Used by serde, tokio, thiserror, and async-trait.

27

What is the thiserror crate used for?

B

Correct Answer

A derive macro that generates error boilerplate (Display, Error, From) for custom error types

Explanation

#[derive(Error)] #[error("file {path} not found")] struct FileNotFound { path: String } generates Display and std::error::Error implementation.

28

What is the anyhow crate?

B

Correct Answer

A crate providing anyhow::Error (a type-erased error) for application code where error type doesn't matter, using context() to add messages

Explanation

fn main() -> anyhow::Result<()> with ? on any error. file.read_to_string().context("reading config") adds context. Use thiserror for library errors, anyhow for apps.

29

What is Rust's cfg! macro and #[cfg] attribute?

B

Correct Answer

Compile-time conditional compilation based on platform, features, or custom flags

Explanation

#[cfg(target_os = "linux")] fn platform_func() compiles only on Linux. cfg!(debug_assertions) is a bool constant. Used for platform-specific code and feature gates.

30

What is Rust's const generics?

B

Correct Answer

Generic parameters that can be compile-time constant values (not just types), like array length: struct FixedArray<T, const N: usize>

Explanation

fn zeros<const N: usize>() -> [i32; N] { [0; N] } creates zero arrays of any size. [T; N] arrays are const-generic over N in std.

31

What is the std::mem::discriminant function?

B

Correct Answer

Returns an opaque value representing which enum variant is active, useful for comparing variants without caring about associated values

Explanation

discriminant(&MyEnum::Foo) == discriminant(&MyEnum::Foo) is true. Lets you compare variant identity without destructuring, even when associated values differ.

32

What is Rust's std::hint::black_box?

B

Correct Answer

A function that prevents the compiler from optimizing away computations in benchmarks

Explanation

criterion benchmarks use black_box(input) to prevent the optimizer from constant-folding the benchmark away, ensuring accurate measurements.

33

What is the From<&str> for String vs Into<String> pattern?

B

Correct Answer

String::from("hello") uses From; "hello".to_string() and "hello".into() (when context is String) use Into. All are zero-overhead allocations

Explanation

Because From<T> for U is implemented, U: Into<T> is auto-implemented. Function parameters using impl Into<String> accept both String and &str without explicit conversion.

34

What is Rust's once_cell crate and how is it now in std?

B

Correct Answer

A crate providing OnceCell<T> and OnceLock<T> for lazy one-time initialization; stabilized as std::cell::OnceLock and std::sync::OnceLock in Rust 1.70

Explanation

static LOG: OnceLock<Logger> = OnceLock::new(); LOG.get_or_init(|| Logger::new()) initializes exactly once across all threads. Replaces lazy_static! macro.

35

What is std::sync::mpsc?

A

Correct Answer

Multi-producer, single-consumer channel for message passing

Explanation

std::sync::mpsc (multi-producer, single-consumer) provides channel::<T>() returning (Sender<T>, Receiver<T>). Sender can be cloned for multiple producers.

36

What is Rust's associated const in a trait?

B

Correct Answer

A trait item that is a compile-time constant value each implementing type must provide

Explanation

trait HasMax { const MAX: u32; } impl HasMax for u8 { const MAX: u32 = 255; } provides a per-type compile-time constant.

37

What does the std::mem::forget function do?

B

Correct Answer

Consumes a value without running its destructor, leaking any resources it owns

Explanation

mem::forget(value) is safe but leaks resources. Used when transferring ownership to C code (ManuallyDrop is preferred), or implementing FFI handshakes.

38

What is the difference between String::new() and String::with_capacity(n)?

B

Correct Answer

String::new() allocates no heap memory initially; with_capacity(n) pre-allocates n bytes, avoiding reallocations when building strings incrementally

Explanation

Pre-allocating with String::with_capacity(100) avoids multiple reallocations when pushing chars or appending substrings in a loop.

39

What is the Entry API for HashMap in Rust?

B

Correct Answer

A way to insert or modify a value only if the key is absent or present, avoiding redundant lookups via map.entry(key).or_insert(default)

Explanation

counts.entry(word).and_modify(|c| *c += 1).or_insert(1) increments if present, inserts 1 if absent — all in one lookup.

40

What is the difference between map() and and_then() on Option/Result?

B

Correct Answer

map() transforms the inner value, wrapping the result back; and_then() (flatMap) passes the inner value to a closure that returns Option/Result itself, avoiding double wrapping

Explanation

opt.map(|x| x + 1) returns Option<i32>. opt.and_then(|x| if x > 0 { Some(x) } else { None }) flattens Option<Option<i32>> into Option<i32>.

1

What is the Non-Lexical Lifetimes (NLL) improvement?

B

Correct Answer

The borrow checker analyzing actual live ranges of borrows rather than lexical scopes, reducing false-positive borrow errors

Explanation

NLL allows let x = v[0]; v.push(y); to compile — x's borrow ends before the push. Prior to NLL, any &v reference blocked mutation for the entire lexical scope.

2

What is variance in Rust lifetimes?

B

Correct Answer

Whether substituting a subtype for a type parameter is allowed: covariant (safe to substitute longer), contravariant (shorter), or invariant (exact)

Explanation

&'a T is covariant over 'a and T. &'a mut T is covariant over 'a but invariant over T (to prevent unsound mutations). PhantomData affects variance.

3

What is the difference between associated types and generic type parameters in traits?

B

Correct Answer

Associated types (type Output) bind one type per implementation (cleaner API); generics (T) allow multiple implementations per type for different T

Explanation

Iterator has type Item (one per impl). If it were generic Iterator<Item>, you could implement multiple Iterators for the same type with different items.

4

What is the Higher-Ranked Trait Bound (HRTB) for<'a>?

B

Correct Answer

A bound meaning the trait must hold for all possible lifetimes: where F: for<'a> Fn(&'a str) -> &'a str

Explanation

HRTB are needed when a closure must work with any lifetime. fn apply<F: for<'a> Fn(&'a i32) -> &'a i32>(f: F) expresses that F is valid for any concrete lifetime 'a.

5

What is the Polonius borrow checker?

B

Correct Answer

A next-generation borrow checker based on Datalog queries that is more precise, accepting more valid programs than NLL

Explanation

Polonius models borrows as facts and uses Datalog to compute liveness. It accepts some patterns that NLL incorrectly rejects while maintaining soundness.

6

What is unsafe trait and unsafe impl?

B

Correct Answer

Unsafe traits (Send, Sync, GlobalAlloc) have safety invariants the compiler cannot check; unsafe impl promises the programmer upholds them

Explanation

unsafe trait Scary {} means implementing it is unsafe. unsafe impl Scary for MyType {} promises the programmer satisfies the contract. Send and Sync are unsafe traits.

7

What is the global allocator in Rust?

B

Correct Answer

A type implementing GlobalAlloc that replaces the default allocator for all heap allocations in the program

Explanation

#[global_allocator] static A: MyAllocator = MyAllocator; replaces the default allocator. Used for embedded systems, tracking allocations, or custom memory management.

8

What is specialization in Rust?

B

Correct Answer

An unstable feature allowing more specific trait implementations to override more general ones, enabling performance optimizations

Explanation

Specialization (RFC 1210, nightly-only) allows a blanket impl to be overridden by a more specific one. Used by the standard library (e.g., ToString being faster for types that impl Display).

9

What is the impact of Rust's zero-cost abstractions?

B

Correct Answer

High-level abstractions (iterators, closures, generics) compile to the same machine code as hand-written low-level equivalents, with no runtime overhead

Explanation

Rust's iterator chains, closures, and monomorphized generics are inlined and optimized to tight loops by LLVM, matching hand-optimized C performance.

10

What is async cancellation in Rust and why is it unique?

B

Correct Answer

Dropping a future cancels it — any awaited work is abandoned. This is synchronous and immediate but requires care for cleanup (select! cancellation safety)

Explanation

In Rust async, dropping a future stops it without any explicit cancel API. This is efficient but requires careful design around cancellation safety (e.g., don't cancel mid-transaction).

11

What is Rust's async runtime and why isn't one built-in?

B

Correct Answer

Rust intentionally leaves the async executor out of std to allow domain-specific runtimes (tokio, async-std, embassy) with different tradeoffs

Explanation

std only provides Future and async/await syntax. tokio is optimized for network I/O. embassy runs on embedded (no_std). smol is minimal. Different use cases need different executors.

12

What is the difference between tokio::spawn and std::thread::spawn in Rust?

B

Correct Answer

tokio::spawn creates a lightweight async task run on the tokio runtime; thread::spawn creates an OS thread with its own stack

Explanation

tokio::spawn creates Tasks — lightweight async work units. thread::spawn creates OS threads with ~8MB stack. You can run millions of Tasks; thousands of threads struggle.

13

What is the Miri interpreter for Rust?

B

Correct Answer

An interpreter for Rust MIR (Mid-level IR) that detects undefined behavior in unsafe code: use-after-free, out-of-bounds, invalid values

Explanation

cargo miri test runs tests under the Miri interpreter, catching UB that ASan/TSan might miss (invalid enum discriminants, uninitialized reads). Slow but thorough.

14

What is Rust's MIR (Mid-level Intermediate Representation)?

B

Correct Answer

A simplified control-flow graph representation used internally for borrow checking, optimization, and code generation before LLVM IR

Explanation

MIR is Rust's internal representation after type checking. The borrow checker runs on MIR. It's also used by Miri, cargo check optimizations, and constant evaluation.

15

What is soundness in Rust's type system?

B

Correct Answer

The property that safe Rust code can never cause undefined behavior; a library is sound if all valid uses of its public safe API cannot cause UB

Explanation

Soundness is Rust's core guarantee. A library with unsafe internals is sound if its safe interface cannot be misused to cause UB. Unsound APIs are bugs.

16

What is the Stacked Borrows memory model for Rust unsafe code?

B

Correct Answer

A formal operational model for memory accesses in Rust that defines when unsafe code causes undefined behavior via aliasing violations

Explanation

Stacked Borrows (Miri uses it) defines a stack of "borrows" per memory location. Accessing via an invalidated borrow or creating forbidden aliasing is UB.

17

What is the Rust portability lint and unsafe guidelines?

B

Correct Answer

The Unsafe Code Guidelines (UCG) define what unsafe Rust code may assume and is allowed to do, forming the basis of Rust's UB model

Explanation

The UCG (unstable, evolving) specifies allowed behaviors for unsafe code: layout guarantees, pointer provenance, aliasing. Violating UCG is UB even if it appears to work.

18

What is the difference between Arc<Mutex<T>> and Arc<RwLock<T>>?

B

Correct Answer

Arc<Mutex<T>> allows only one accessor at a time; Arc<RwLock<T>> allows concurrent reads but exclusive writes — better when reads are frequent

Explanation

RwLock has higher acquisition overhead than Mutex. For write-heavy or short-duration access, Mutex may outperform. Measure before switching.

19

What is the pinning contract and self-referential structs?

B

Correct Answer

Pin<P> guarantees the pointee won't move; self-referential structs (holding pointers to their own fields) require Pin because moving would invalidate the pointer

Explanation

Async state machines contain references to their own stack variables. Pin prevents moves after these references are created. unsafe impl Unpin on a self-referential type is unsound.

20

What is Rust's strict provenance model for raw pointers?

B

Correct Answer

Pointers carry provenance (metadata about their origin) beyond the address; casting integers to pointers may lose provenance, causing UB under strict models

Explanation

Strict provenance (ptr::from_exposed_addr, ptr.addr(), ptr.with_addr()) preserves pointer provenance information, making Rust's memory model compatible with address sanitizers and formal verification.