Appendix D — Rust Interview Toolkit
The Rust examples form one standard-library-only Cargo package. They use ownership explicitly but keep types and iterator chains small enough to reproduce under interview pressure.
D.1 Slices and vectors
Prefer a borrowed slice when the algorithm only reads input:
pub fn search(nums: &[i32], target: i32) -> Option<usize>| API | Interview use |
|---|---|
nums.len() |
item count |
nums.iter() |
borrow each item |
nums.to_vec() |
make an owned copy |
values.push(x) |
append to a Vec |
vec![value; n] |
initialized vector |
Indices are usize. Half-open intervals such as [low, high) often avoid subtracting from zero.
D.2 Option and Result
Option<T> expresses a value that may be absent without a sentinel:
if let Some(&earlier_index) = index_by_value.get(&needed) {
return Some([earlier_index, index]);
}Use Result<T, E> when construction can fail and the reason matters, as in validated intervals. In interview code, ?, if let, let ... else, and match cover most control flow.
D.3 Hash maps and queues
std::collections::HashMap provides expected \(O(1)\) lookup and insertion. entry is useful for grouping and counting:
groups.entry(key).or_insert_with(Vec::new).push(word);
*frequency.entry(word).or_insert(0) += 1;VecDeque is the standard FIFO queue. Use push_back, pop_front, and len for breadth-first traversal.
D.4 Sorting and ordering
slice.sort() uses natural order. sort_by_key works when a key can be produced cheaply; sort_by handles borrowed data and mixed directions:
ranked.sort_by(|left, right| {
frequency[right]
.cmp(&frequency[left])
.then_with(|| left.cmp(right))
});For floating-point endpoints, f64::total_cmp supplies a total ordering. Validate away non-finite values when the problem contract requires finite endpoints.
D.5 Strings and characters
str is UTF-8 and cannot be indexed by an integer. Use text.chars() for Unicode scalar values or text.bytes() when the contract is explicitly ASCII:
for (index, character) in text.chars().enumerate() {
// character index, not byte offset
}Clarify whether the problem expects bytes, scalar values, or user-perceived grapheme clusters.
D.6 Owned linked nodes
An acyclic owned link is conventionally:
type Link = Option<Box<ListNode>>;take() detaches an owned link before rewiring it. This makes node reuse visible to the compiler and avoids copying data nodes.
Cycles require shared ownership. The cycle example uses Rc<RefCell<ListNode>>: Rc provides multiple owners, RefCell permits checked interior mutation while building fixtures, and Rc::ptr_eq compares identity. Use this heavier representation only when the structure truly needs shared or cyclic links.
D.7 Borrowed trees
Option<Box<TreeNode>> owns child nodes. Traversals can borrow through as_deref(), placing &TreeNode references in a queue or returning a reference tied to the tree’s lifetime. This avoids cloning or moving the tree.
D.8 Cargo tests
Tests live beside each solution under #[cfg(test)]:
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ordinary_case() {
assert_eq!(expected, function(input));
}
}From book/src/rust, run every test with cargo test or filter one module with cargo test two_sum_solution.