***1. Create a Rust program that reads data from a file and counts occurrences of a word.

This program:

  • Reads a file
  • Counts occurrences of a target word
  • Demonstrates file handling and string processing

Rust Program

use std::fs;

fn main() {
let filename = "data.txt";
let target_word = "rust";

let content = fs::read_to_string(filename)
.expect("Failed to read file");

let count = content
.split_whitespace()
.filter(|word| word.to_lowercase() == target_word)
.count();

println!("Occurrences of '{}': {}", target_word, count);
}

Example Input File

Rust is fast.
Rust is memory safe.
I love Rust.

Output

Occurrences of 'rust': 3

Important Concepts

ConceptUsage
fs::read_to_stringRead file
split_whitespaceTokenize words
filterMatch target word
countCount matches

Interview Tip

Mention:

  • Error handling
  • Case-insensitive comparison
  • Efficient string processing

***2. Reverse a string without using built-in reverse methods.

This question tests:

  • String iteration
  • Character handling
  • Ownership concepts

Rust Program

fn reverse_string(input: &str) -> String {
let mut reversed = String::new();

for ch in input.chars() {
reversed = format!("{}{}", ch, reversed);
}

reversed
}

fn main() {
let text = "Rust";

let result = reverse_string(text);

println!("Reversed: {}", result);
}

Output

Reversed: tsuR

Important Concepts

ConceptUsage
chars()Iterate characters
StringDynamic string building
UTF-8 safetyProper char handling

Time Complexity

O(n²)

because repeated string concatenation reallocates memory.


Optimized Version

fn reverse_string(input: &str) -> String {
let mut chars: Vec<char> = input.chars().collect();

let mut left = 0;
let mut right = chars.len() - 1;

while left < right {
chars.swap(left, right);

left += 1;
right -= 1;
}

chars.into_iter().collect()
}

Interview Tip

Discuss:

  • UTF-8 correctness
  • Complexity optimization
  • Manual algorithm implementation

***3. Implement factorial using recursion and iteration.

This question tests:

  • Recursion
  • Loops
  • Base cases
  • Performance understanding

Recursive Factorial

fn factorial_recursive(n: u64) -> u64 {
if n == 0 || n == 1 {
1
} else {
n * factorial_recursive(n - 1)
}
}

Iterative Factorial

fn factorial_iterative(n: u64) -> u64 {
let mut result = 1;

for i in 2..=n {
result *= i;
}

result
}

Main Function

fn main() {
let num = 5;

println!("Recursive: {}", factorial_recursive(num));
println!("Iterative: {}", factorial_iterative(num));
}

Output

Recursive: 120
Iterative: 120

Recursion vs Iteration

FeatureRecursionIteration
ReadabilitySimplerEfficient
Stack UsageHigherLower
PerformanceSlightly slowerFaster

Interview Tip

Mention:

  • Stack overflow risk
  • Tail recursion limitations
  • Iterative optimization

***4. Find duplicates in a vector.

This problem tests:

  • Hashing
  • Collections
  • Time complexity optimization

Rust Program

use std::collections::HashSet;

fn find_duplicates(nums: Vec<i32>) {
let mut seen = HashSet::new();
let mut duplicates = HashSet::new();

for num in nums {
if !seen.insert(num) {
duplicates.insert(num);
}
}

println!("Duplicates: {:?}", duplicates);
}

fn main() {
let numbers = vec![1, 2, 3, 2, 4, 5, 1];

find_duplicates(numbers);
}

Output

Duplicates: {1, 2}

Time Complexity

OperationComplexity
Insert/SearchO(1) average
OverallO(n)

Why HashSet?

HashSet provides:

  • Fast lookup
  • Unique storage
  • Efficient duplicate detection

Interview Tip

Mention:

  • Time complexity
  • Space trade-offs
  • Alternative sorting solution

***5. Create a simple HTTP server in Rust.

This project demonstrates:

  • Networking
  • TCP handling
  • HTTP basics

Rust Program

use std::io::{Read, Write};
use std::net::TcpListener;

fn main() {
let listener = TcpListener::bind("127.0.0.1:8080")
.expect("Failed to bind");

println!("Server running on port 8080");

for stream in listener.incoming() {
let mut stream = stream.unwrap();

let mut buffer = [0; 1024];

stream.read(&mut buffer).unwrap();

let response =
"HTTP/1.1 200 OK\r\n\r\nHello from Rust!";

stream.write(response.as_bytes()).unwrap();

stream.flush().unwrap();
}
}

How It Works

ComponentPurpose
TcpListenerListen for connections
incoming()Accept clients
stream.read()Read request
stream.write()Send response

Test in Browser

http://127.0.0.1:8080

Interview Tip

Discuss:

  • Blocking I/O limitations
  • Async alternatives
  • HTTP parsing improvements

***6. Write a Rust networking program to send data between two machines.

This demonstrates:

  • TCP communication
  • Client-server networking
  • Socket programming

Server Code

use std::io::Read;
use std::net::TcpListener;

fn main() {
let listener = TcpListener::bind("0.0.0.0:8080").unwrap();

println!("Server listening...");

for stream in listener.incoming() {
let mut stream = stream.unwrap();

let mut buffer = [0; 1024];

let bytes = stream.read(&mut buffer).unwrap();

println!(
"Received: {}",
String::from_utf8_lossy(&buffer[..bytes])
);
}
}

Client Code

use std::io::Write;
use std::net::TcpStream;

fn main() {
let mut stream =
TcpStream::connect("127.0.0.1:8080").unwrap();

stream.write_all(b"Hello from client").unwrap();
}

Networking Concepts

ConceptPurpose
TCPReliable communication
SocketConnection endpoint
StreamData transfer

Interview Tip

Mention:

  • Error handling
  • Async networking
  • Serialization formats

***7. Build a multithreaded web scraper in Rust.

This project demonstrates:

  • Concurrency
  • Networking
  • Thread management

Cargo Dependencies

[dependencies]
reqwest = { version = "0.11", features = ["blocking"] }

Rust Program

use std::thread;

fn fetch(url: &str) {
let body = reqwest::blocking::get(url)
.unwrap()
.text()
.unwrap();

println!("Fetched {} bytes from {}", body.len(), url);
}

fn main() {
let urls = vec![
"https://example.com",
"https://rust-lang.org",
];

let mut handles = vec![];

for url in urls {
let url = url.to_string();

let handle = thread::spawn(move || {
fetch(&url);
});

handles.push(handle);
}

for handle in handles {
handle.join().unwrap();
}
}

Key Concepts

ConceptPurpose
thread::spawnParallel tasks
moveOwnership transfer
join()Wait for completion

Interview Tip

Discuss:

  • Async alternative using Tokio
  • Rate limiting
  • Error retries

***8. Implement producer-consumer using channels.

This demonstrates:

  • Thread communication
  • Message passing concurrency

Rust Program

use std::sync::mpsc;
use std::thread;

fn main() {
let (tx, rx) = mpsc::channel();

thread::spawn(move || {
for i in 1..=5 {
tx.send(i).unwrap();

println!("Produced {}", i);
}
});

for received in rx {
println!("Consumed {}", received);
}
}

Output

Produced 1
Consumed 1
...

Important Concepts

ConceptPurpose
ChannelThread communication
ProducerSends data
ConsumerReceives data

Why Channels Matter

Channels:

  • Avoid shared mutable state
  • Simplify concurrency
  • Improve safety

Interview Tip

Mention:

  • Multiple producers
  • Buffered channels
  • Async channels

***9. Build a CLI todo app using Cargo.

This project demonstrates:

  • CLI development
  • File persistence
  • Cargo usage

Cargo Command

cargo new todo_app

Rust Program

use std::env;

fn main() {
let args: Vec<String> = env::args().collect();

if args.len() < 3 {
println!("Usage: todo add <task>");
return;
}

let command = &args[1];
let task = &args[2];

match command.as_str() {
"add" => {
println!("Task added: {}", task);
}

_ => {
println!("Unknown command");
}
}
}

Example Usage

cargo run add "Learn Rust"

Improvements

Possible enhancements:

  • File storage
  • JSON persistence
  • Task deletion
  • Colored output

Interview Tip

Discuss:

  • CLI parsing libraries
  • Persistent storage
  • Error handling

***10. Build an async REST API using Tokio + Axum/Actix.

This demonstrates:

  • Async Rust
  • Web APIs
  • Tokio runtime

Cargo Dependencies

[dependencies]
tokio = { version = "1", features = ["full"] }
axum = "0.7"

Rust Program

use axum::{routing::get, Router};

async fn hello() -> &'static str {
"Hello, Rust API!"
}

#[tokio::main]
async fn main() {
let app = Router::new()
.route("/", get(hello));

let listener =
tokio::net::TcpListener::bind("0.0.0.0:3000")
.await
.unwrap();

axum::serve(listener, app)
.await
.unwrap();
}

Test API

http://localhost:3000

Key Concepts

ConceptPurpose
TokioAsync runtime
AxumWeb framework
Async handlerNon-blocking request handling

Interview Tip

Discuss:

  • Middleware
  • Database integration
  • Authentication

***11. Implement a thread pool from scratch.

This project demonstrates:

  • Concurrency
  • Worker threads
  • Task scheduling

Core Components

ComponentPurpose
Worker threadsExecute tasks
ChannelTask queue
ThreadPoolManage workers

Simplified Thread Pool

use std::sync::{mpsc, Arc, Mutex};
use std::thread;

type Job = Box<dyn FnOnce() + Send + 'static>;

struct ThreadPool {
workers: Vec<thread::JoinHandle<()>>,
sender: mpsc::Sender<Job>,
}

impl ThreadPool {
fn new(size: usize) -> Self {
let (sender, receiver) = mpsc::channel();

let receiver = Arc::new(Mutex::new(receiver));

let mut workers = vec![];

for _ in 0..size {
let receiver = Arc::clone(&receiver);

let handle = thread::spawn(move || {
loop {
let job = receiver
.lock()
.unwrap()
.recv()
.unwrap();

job();
}
});

workers.push(handle);
}

Self { workers, sender }
}
}

Interview Tip

Discuss:

  • Graceful shutdown
  • Work stealing
  • Async executors comparison

***12. Build a mini key-value store in Rust.

This project demonstrates:

  • HashMap usage
  • Persistence concepts
  • CRUD operations

Rust Program

use std::collections::HashMap;

fn main() {
let mut store = HashMap::new();

store.insert("name", "Rust");
store.insert("type", "language");

println!("{:?}", store.get("name"));
}

Key Concepts

ConceptPurpose
HashMapKey-value storage
Insert/GetCRUD operations
PersistenceFuture enhancement

Possible Improvements

  • File persistence
  • Async networking
  • WAL logging
  • LSM tree

Interview Tip

Mention:

  • Database internals
  • Concurrency handling
  • Disk persistence

***13. Create a custom smart pointer.

This demonstrates:

  • Deref trait
  • Smart pointer internals

Rust Program

use std::ops::Deref;

struct MyBox<T>(T);

impl<T> MyBox<T> {
fn new(value: T) -> Self {
MyBox(value)
}
}

impl<T> Deref for MyBox<T> {
type Target = T;

fn deref(&self) -> &Self::Target {
&self.0
}
}

fn main() {
let x = MyBox::new(10);

println!("{}", *x);
}

Key Concepts

ConceptPurpose
DerefPointer behavior
Generic typesReusability
Smart pointersOwnership abstraction

Interview Tip

Discuss:

  • Drop
  • Deref coercion
  • Heap allocation

***14. Implement a lock-free queue.

This is an advanced concurrency/system design problem.

Lock-free structures use:

  • Atomic operations
  • Compare-and-swap (CAS)

Simplified Concept

Head -> Node -> Node

Threads modify pointers atomically.


Basic Atomic Example

use std::sync::atomic::{AtomicUsize, Ordering};

fn main() {
let counter = AtomicUsize::new(0);

counter.fetch_add(1, Ordering::SeqCst);

println!("{}", counter.load(Ordering::SeqCst));
}

Real Lock-Free Queue Requirements

A production implementation requires:

  • Atomic linked list operations
  • Memory reclamation
  • ABA prevention
  • Hazard pointers/epoch GC

Popular Library

Many Rust projects use:

  • crossbeam

for lock-free data structures.


Interview Tip

For interviews:

  • Explain atomic CAS operations
  • Discuss ABA problem
  • Mention memory ordering semantics