Rust Challenges for Fearless Concurrency
Rust is a language built for performance, reliability, and productivity. For developers, mastering Rust’s unique ownership model and fearless concurrency opens up opportunities in systems programming, web assembly, and beyond. For employers, finding engineers who can write safe, efficient, and concurrent code is a top priority.
That’s why we’ve put together this collection of 30 hands-on Rust challenges. We’ve organized them into three levels—10 for Junior, 10 for Mid-Level, and 10 for Senior developers—to help you build your skills, prepare for your next interview, or find the perfect candidate for your team.
Jump to Your Level
| Junior Developer | ⚙️ Mid-Level Developer | Senior Developer |
Junior Developer Challenges
1. Hello, World!
The traditional first program to verify a working setup.
fn main() {
println!("Hello, World!");
}2. Sum of a Vector of Integers
A basic test of loops and vector manipulation.
fn sum(numbers: &Vec) -> i32 {
let mut total = 0;
for &num in numbers {
total += num;
}
total
} 3. Reverse a String
A simple test of string manipulation.
fn reverse(s: &str) -> String {
s.chars().rev().collect()
}4. Find the Largest Number in a Slice
A fundamental algorithm using a simple loop.
fn largest(list: &[i32]) -> i32 {
let mut largest = list[0];
for &item in list {
if item > largest {
largest = item;
}
}
largest
}5. Check if a String is a Palindrome
Tests string manipulation and comparison logic.
fn is_palindrome(s: &str) -> bool {
let reversed: String = s.chars().rev().collect();
s == reversed
}6. FizzBuzz
The classic test of basic conditional logic and loops.
fn fizzbuzz(n: u32) {
for i in 1..=n {
if i % 15 == 0 {
println!("FizzBuzz");
} else if i % 3 == 0 {
println!("Fizz");
} else if i % 5 == 0 {
println!("Buzz");
} else {
println!("{}", i);
}
}
}7. Simple `struct` for a `Person`
Introduces custom types and data organization.
struct Person {
name: String,
age: u32,
}8. Function that returns an `Option`
A simple function to demonstrate optional values.
fn find_user(id: u32) -> Option {
if id == 1 {
Some("Alice".to_string())
} else {
None
}
} 9. Simple Loop to Print Numbers 1-10
A basic loop to demonstrate syntax.
fn print_numbers() {
for i in 1..=10 {
println!("{}", i);
}
}10. Check if a Number is Positive, Negative, or Zero
Tests basic conditional logic.
fn check_number(n: i32) {
if n > 0 {
println!("Positive");
} else if n < 0 {
println!("Negative");
} else {
println!("Zero");
}
}Mid-Level Developer Challenges
1. Word Count in a String using a `HashMap`
Use a `HashMap` to count the frequency of words in a text.
use std::collections::HashMap;
fn word_count(text: &str) -> HashMap {
let mut map = HashMap::new();
for word in text.split_whitespace() {
let count = map.entry(word.to_string()).or_insert(0);
*count += 1;
}
map
} 2. Implement a Simple Trait
A simple trait for a `Shape` with an `area` method.
trait Shape {
fn area(&self) -> f64;
}
struct Circle {
radius: f64,
}
impl Shape for Circle {
fn area(&self) -> f64 {
std::f64::consts::PI * self.radius * self.radius
}
}3. JSON Serialization and Deserialization with `serde`
Convert Rust structs to and from JSON using the `serde` crate.
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
struct User {
name: String,
age: u32,
}4. Find the First Non-Repeating Character in a String
A common interview question that can be solved with a `HashMap`.
use std::collections::HashMap;
fn first_non_repeating_character(s: &str) -> Option {
let mut counts = HashMap::new();
for c in s.chars() {
*counts.entry(c).or_insert(0) += 1;
}
for c in s.chars() {
if counts[&c] == 1 {
return Some(c);
}
}
None
} 5. Implement a Simple Generic Function
A simple generic function that takes a slice of any type that implements the `Display` trait.
use std::fmt::Display;
fn print_slice(slice: &[T]) {
for item in slice {
println!("{}", item);
}
} 6. Error Handling with `Result`
A simple example of error handling with `Result
fn divide(a: f64, b: f64) -> Result {
if b == 0.0 {
Err("Cannot divide by zero".to_string())
} else {
Ok(a / b)
}
} 7. Use of Closures
A simple example of a closure.
fn main() {
let add_one = |x| x + 1;
println!("{}", add_one(1));
}8. Implement a Simple Command-Line Argument Parser
A simple command-line argument parser.
use std::env;
fn main() {
let args: Vec = env::args().collect();
println!("{:?}", args);
} 9. Read and Write to a File
A simple example of reading and writing to a file.
use std::fs;
fn main() -> std::io::Result<()> {
fs::write("foo.txt", "Hello, world!")?;
let contents = fs::read_to_string("foo.txt")?;
println!("{}", contents);
Ok(())
}10. Implement a Simple Linked List
A simple implementation of a linked list.
enum List {
Cons(i32, Box),
Nil,
}
Senior Developer Challenges
1. Implement a Thread-Safe Counter using `Arc>`
A thread-safe counter using `Arc
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Result: {}", *counter.lock().unwrap());
}2. Create a Simple Web Server with `tokio`
A simple web server with `tokio`.
use tokio::net::{TcpListener, TcpStream};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
#[tokio::main]
async fn main() -> Result<(), Box> {
let listener = TcpListener::bind("127.0.0.1:8080").await?;
loop {
let (mut socket, _) = listener.accept().await?;
tokio::spawn(async move {
// ...
});
}
} 3. Implement a Simple Memory Allocator
A simple memory allocator.
use std::alloc::{GlobalAlloc, Layout, System};
struct MyAllocator;
unsafe impl GlobalAlloc for MyAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
System.alloc(layout)
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
System.dealloc(ptr, layout)
}
}
#[global_allocator]
static GLOBAL: MyAllocator = MyAllocator;4. Write a Macro
A simple macro.
macro_rules! five {
() => {
5
};
}
fn main() {
println!("{}", five!());
}5. Implement a Simple Async Runtime
A simple async runtime.
// This is a complex task that would require a lot of code.
// A full implementation would be too long for this format.6. Use of Unsafe Rust to Interact with C Code
A simple example of using unsafe Rust to interact with C code.
extern "C" {
fn abs(input: i32) -> i32;
}
fn main() {
unsafe {
println!("Absolute value of -3 is {}", abs(-3));
}
}7. Implement a Simple Concurrent Queue
A simple concurrent queue.
use std::collections::VecDeque;
use std::sync::{Arc, Condvar, Mutex};
struct ConcurrentQueue {
inner: Arc<(Mutex>, Condvar)>,
} 8. Write a Simple Key-Value Store
A simple key-value store.
use std::collections::HashMap;
struct KvStore {
map: HashMap,
}
impl KvStore {
fn new() -> KvStore {
KvStore {
map: HashMap::new(),
}
}
fn set(&mut self, key: String, value: String) {
self.map.insert(key, value);
}
fn get(&self, key: &str) -> Option<&String> {
self.map.get(key)
}
} 9. Implement a Simple State Machine
A simple state machine.
enum State {
Start,
Running,
Stop,
}
struct StateMachine {
state: State,
}
impl StateMachine {
fn new() -> StateMachine {
StateMachine {
state: State::Start,
}
}
fn transition(&mut self, new_state: State) {
self.state = new_state;
}
}10. Create a Simple Build Script for a Crate
A simple build script for a crate.
// In build.rs
fn main() {
println!("cargo:rerun-if-changed=src/hello.c");
cc::Build::new().file("src/hello.c").compile("hello");
}Tips to Prepare for Rust Coding Challenges
- Master Ownership and Borrowing: This is the most fundamental concept in Rust. Understand how the borrow checker works and how to use references (`&` and `&mut`) effectively.
- Know Your Lifetimes: For any non-trivial program, you'll need to understand lifetimes. Practice writing functions that take and return references.
- Use `Option` and `Result`: Rust's error handling is built around these enums. Practice using them instead of panicking.
- Understand Traits: Traits are Rust's way of defining shared behavior. Practice implementing traits for your own types.
- Use `clippy`: The `clippy` linter is an invaluable tool for writing idiomatic Rust. Use it often.
Conclusion
Rust's focus on safety, speed, and concurrency makes it a powerful tool for building robust software. By practicing with these challenges, you'll be well-prepared to tackle any interview and build amazing applications. Happy coding!


