Skip to content

Expert · Rust careers and interviews · topic 49 of 50 · 35 min

Interview questions: traits, errors, pointers and concurrency

Explanation

After ownership, interviews move to traits and generics (static versus dynamic dispatch), error handling (Option, Result, ?, panic), smart pointers (Box, Rc, RefCell, Arc), concurrency (Send, Sync, Mutex, channels) and async (futures, runtimes, blocking). Expect short "what does this print" or "why does this not compile" snippets too.

Q1. Generics versus trait objects?

Model answer: "Generics use static dispatch: the compiler makes a specialised copy for each type (monomorphization), so calls are fast and can be inlined, but binaries grow. Trait objects (dyn Trait behind a pointer) use dynamic dispatch through a vtable: one copy of the code, a small cost per call, and they allow mixing types in one collection or choosing the type at run time."

Q2. Option versus Result? When do you panic?

Model answer: "Option means a value may be absent; Result means an operation may fail and carries an error. I return Result for expected failures like bad input or I/O, and use ? to propagate errors. I panic only for bugs or impossible states, and in tests or prototypes. Libraries should rarely panic."

Q3. What does ? do exactly?

Model answer: "On Ok or Some it unwraps the value. On Err it converts the error with From::from and returns it from the current function; on None it returns None. It only works in functions whose return type can carry that early return."

Q4. Box, Rc, Arc, RefCell, Mutex: when each?

PointerOne-line answer
Box<T>Single owner on the heap; recursive types and trait objects
Rc<T>Shared ownership in one thread, read-only
Arc<T>Shared ownership across threads (atomic count)
RefCell<T>Interior mutability in one thread, borrow rules checked at run time
Mutex<T> / RwLock<T>Interior mutability across threads, with locking

Q5. What are Send and Sync?

Model answer: "Send means a value can be moved to another thread; Sync means a shared reference to it can be used from several threads. They are auto traits: the compiler derives them from a type's fields. Rc is neither, because its counter is not atomic; Arc<Mutex<T>> is both when T is Send."

Q6. Does Rust prevent deadlocks?

Model answer: "No. Safe Rust prevents data races, but deadlocks and logic bugs are still possible. I avoid them by keeping lock scopes short, never awaiting or calling unknown code while holding a lock, and taking multiple locks in a consistent order."

Q7. Threads or async?

Model answer: "Async suits many I/O-bound tasks, such as thousands of network connections, on a runtime like tokio with few threads. Threads suit CPU-bound work. Futures are lazy and need a runtime; blocking calls inside async code stall the runtime, so heavy work goes to spawn_blocking or a thread pool."

Q8. Quick-fire snippets

rust
let v = vec![1, 2, 3];
let w = v;
println!("{}", v.len());          // does not compile: v was moved (E0382)

let x: Option<u32> = None;
println!("{}", x.unwrap_or(7));   // prints 7

let s = String::from("hi");
let t = &s;
let u = &s;
println!("{t}{u}");               // prints hihi: two shared borrows are fine
Explain each answer in one sentence.

A take-home assignment checklist

  • Clear README: how to build, run and test; design decisions.
  • cargo fmt, cargo clippy with no warnings, and passing tests.
  • Errors handled with Result and good messages; no unwrap on user input.
  • Small modules with clear names; logic in lib.rs.
  • A few meaningful tests, including edge cases.

Common mistakes

  • Saying RefCell makes code thread-safe. It does not; use Mutex or RwLock across threads.
  • Claiming async is always faster. It is better for waiting, not for computing.
  • Using unwrap everywhere in a take-home assignment. Reviewers notice immediately.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Interview questions: traits, errors, pointers and concurrency · 1/6

Traits | Errors | Pointers | Threads | Async

After ownership, interviews cover traits, errors, smart pointers, concurrency and async.

Prefer a video by a teacher? Find free videos on “rust interview questions traits smart pointers concurrency async” on YouTube ↗

In real life: A system-design follow-up

After the basics, an interviewer at a logistics company asks: "We need a service that tracks 50,000 delivery vans sending GPS pings every 5 seconds. How would you build it in Rust?" A strong answer: an axum service on tokio for the many connections, a bounded channel to a small pool of writer tasks for back-pressure, Arc-shared state for the latest positions (perhaps a RwLock or a concurrent map crate), batching database writes, and metrics and tracing for visibility. The answer connects language features to real constraints.

rust
use std::collections::HashMap;
use std::sync::{Arc, RwLock};

type Positions = Arc<RwLock<HashMap<u32, (f64, f64)>>>;   // van id -> (lat, lon)

fn update(p: &Positions, van: u32, lat: f64, lon: f64) {
    p.write().unwrap().insert(van, (lat, lon));
}

fn lookup(p: &Positions, van: u32) -> Option<(f64, f64)> {
    p.read().unwrap().get(&van).copied()
}
Many readers (dashboards), fewer writers (pings): a good fit for RwLock.

Practice (0/3 done)

Task 1 · Question

Which pointer would you use for shared, changeable data across threads?

Task 2 · Question

What does this print? let a: Result<u32, String> = Err("no".into()); println!("{}", a.unwrap_or(5) + 1);

Task 3 · Practice

Do a mock take-home in 3 hours: a CLI or small axum API that manages a library of books (add, list, search, borrow, return) with data saved to a JSON file. Apply the checklist from this topic, then ask a friend or online community to review it.

Quick quiz

Question 1

1.What is monomorphization?

Question 2

2.Is RefCell<T> safe to share between threads?

Question 3

3.What happens if you call a blocking function inside a tokio task?

Question 4

4.Which is a good answer to "When do you panic?"

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

What is monomorphization?

Answer: Generating specialised code for each concrete type used with a generic

It is why generics have no run-time cost.

Is RefCell<T> safe to share between threads?

Answer: No, it is not Sync

Use Mutex or RwLock across threads.

What happens if you call a blocking function inside a tokio task?

Answer: It can stall other tasks on that worker thread

Blocking work belongs in spawn_blocking.

Which is a good answer to "When do you panic?"

Answer: For bugs and impossible states; expected failures return Result

Panics are for programmer errors, not normal failures.

Which statement about Rust and deadlocks is true?Related

Answer: Deadlocks are still possible; avoid them by design

Rust prevents data races, not deadlocks.

From Shared state: Arc, Mutex, Send and Sync

Why does thread::spawn require 'static data?Related

Answer: The thread may outlive any borrowed local data

Spawned threads can run after the caller returns.

From Interview questions: ownership, borrowing and lifetimes

Which type should a ViewModel expose for screen state?Related

Answer: StateFlow

Read-only, always has a value.

From Interview questions: Kotlin

Why must dyn Trait be behind a pointer like Box?Related

Answer: Its size is not known at compile time

Different implementing types have different sizes.

From Trait objects and dynamic dispatch

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 1 more topic in “Rust careers and interviews” before its exam: Portfolio, open source and a learning plan.
  2. Module 12 exam: Rust careers and interviews · 10 questions · 20 min, without help. 4 topics of this module still to finish first.
  3. 50 topics left in the course before the final exam.

← Previous: Interview questions: ownership, borrowing and lifetimes