| You are being evaluated on your Rust programming ability. |
|
|
| Complete all tasks below. Do not skip any task. For each task: |
| 1. Briefly explain your reasoning. |
| 2. Provide compile-ready Rust code. |
| 3. Use idiomatic Rust. |
| 4. Mention important trade-offs or limitations when relevant. |
|
|
| General rules: |
| - Prefer stable Rust. |
| - Use the standard library unless a task explicitly requires an external crate. |
| - If a task requires a crate, include the Cargo.toml dependency snippet. |
| - Do not give pseudo-code unless explicitly asked. |
| - Keep explanations concise but technically accurate. |
|
|
| Output format: |
| - Use section headers: Task 1, Task 2, etc. |
| - For code, use fenced Rust code blocks. |
| - For conceptual questions, give a structured explanation. |
| - If you change a broken snippet, explain exactly why it was broken. |
|
|
| Tasks: |
|
|
| Task 1 β Word frequency |
| Write a function: |
|
|
| fn word_frequency(text: &str) -> std::collections::HashMap<String, usize> |
| |
| Requirements: |
| - Count word frequencies case-insensitively. |
| - Split by whitespace. |
| - Return a HashMap<String, usize>. |
| |
| Task 2 β Borrow checker debugging |
| This code does not compile: |
| |
| fn main() { |
| let mut v = vec![1, 2, 3]; |
| let first = &v[0]; |
| v.push(4); |
| println!("{}", first); |
| } |
| |
| Explain precisely why it fails and fix it with minimal changes. Then show one alternative fix. |
| |
| Task 3 β Lifetimes |
| Implement: |
| |
| fn longest<'a>(a: &'a str, b: &'a str) -> &'a str |
| |
| Then explain why the lifetime annotation is needed. |
| |
| Task 4 β Struct with borrowed data |
| Define a struct: |
| |
| UserView |
| |
| Requirements: |
| - It stores a borrowed user name as &str |
| - It stores age as u32 |
| - Use the correct lifetime annotation |
| - Show a small usage example |
| |
| Task 5 β Result and custom error type |
| Implement: |
| |
| fn parse_positive_int(input: &str) -> Result<u32, ParseNumberError> |
| |
| Requirements: |
| - Return an error if parsing fails |
| - Return an error if the number is zero |
| - Define a custom enum error type named ParseNumberError |
| - Explain why this is better than returning String |
| |
| Task 6 β Generics and trait bounds |
| Implement: |
| |
| fn max_of_two<T: Ord>(a: T, b: T) -> T |
| |
| Then explain why T: Ord is needed. |
| |
| Task 7 β Enums and pattern matching |
| Define an enum for order state with these variants: |
| - Created |
| - Paid |
| - Shipped |
| - Delivered |
| - Cancelled |
| |
| Implement a function: |
| |
| fn can_cancel(status: OrderStatus) -> bool |
|
|
| Explain the business logic encoded in the match. |
|
|
| Task 8 β Recursive enum / AST |
| Create a simple expression AST that supports: |
| - integer literal |
| - addition |
| - multiplication |
|
|
| Implement an evaluator function that computes the result. |
| Use a recursive enum and Box where necessary. |
|
|
| Task 9 β Concurrency |
| Write a Rust program that: |
| - creates a shared counter |
| - spawns 10 threads |
| - each thread increments the counter 1000 times |
| - waits for all threads to finish |
| - prints the final result |
|
|
| Use Arc<Mutex<_>> and explain why both Arc and Mutex are needed. |
|
|
| Task 10 β Async Rust |
| Using tokio, write an example that runs 3 async operations concurrently and waits for all of them. |
|
|
| Requirements: |
| - include the Cargo.toml dependency snippet |
| - use async/await correctly |
| - explain the difference between async concurrency and OS threads at a high level |
|
|
| Task 11 β macro_rules! |
| Write a macro: |
| |
| make_vec! |
|
|
| Requirements: |
| - it accepts any number of arguments |
| - it returns a Vec containing them |
| - show a usage example |
|
|
| Task 12 β Idiomatic Rust / optimization |
| Review this function: |
|
|
| fn greet(name: &str) -> String { |
| format!("Hello, {}", name.to_string()) |
| } |
| |
| Explain what is non-idiomatic or inefficient here and rewrite it more idiomatically. |
|
|
| Task 13 β Testing |
| Write: |
|
|
| fn is_prime(n: u64) -> bool |
| |
| Then add unit tests that cover: |
| - small primes |
| - small non-primes |
| - edge cases such as 0 and 1 |
| |
| Task 14 β Trait object vs generics |
| Explain the difference between: |
| |
| fn draw_all<T: Draw>(items: &[T]) |
|
|
| and |
|
|
| fn draw_all(items: &[Box<dyn Draw>]) |
| |
| Discuss: |
| - static dispatch |
| - dynamic dispatch |
| - monomorphization |
| - when each approach is preferable |
| |
| Task 15 β Architecture |
| Design a simple TCP chat server in Rust. |
| |
| Do not implement the full server. Instead provide: |
| - a module structure |
| - key data structures |
| - where you would use async |
| - where shared state is needed |
| - major risks or failure points |
| - what crates you would likely use and why |
| |
| Final requirement: |
| At the end, add a short self-review with: |
| 1. the two tasks that are most error-prone in Rust, |
| 2. the two places where unsafe Rust might appear in real systems related to these tasks, |
| 3. one example of a common beginner mistake in Rust API design. |