A collection of practical Rust code examples covering common patterns and use cases.

Table of Contents#

  1. CLI Tool (Argument Parsing + Output)
  2. File I/O (Read, Write, Append)
  3. HTTP Server (Blocking, Minimal)
  4. Concurrency (Threads + Channels)
  5. Concurrency (Shared State with Arc + Mutex)
  6. Error Handling Patterns
  7. Struct + Trait + Impl (Complete Example)
  8. Iterator Chaining
  9. Troubleshooting
  10. See also
  11. Sources

CLI Tool (Argument Parsing + Output)#

A minimal command-line tool that reads a file and counts lines, words, or characters.

use std::fs;
use std::env;
use std::process;

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() < 3 {
        eprintln!("Usage: {} <mode> <file>", args[0]);
        eprintln!("  mode: lines | words | chars");
        process::exit(1);
    }

    let mode = &args[1];
    let path = &args[2];

    let content = match fs::read_to_string(path) {
        Ok(c) => c,
        Err(e) => {
            eprintln!("Error reading {}: {}", path, e);
            process::exit(1);
        }
    };

    let count = match mode.as_str() {
        "lines" => content.lines().count(),
        "words" => content.split_whitespace().count(),
        "chars" => content.chars().count(),
        other => {
            eprintln!("Unknown mode: {}. Use lines, words, or chars.", other);
            process::exit(1);
        }
    };

    println!("{}: {}", mode, count);
}

File I/O (Read, Write, Append)#

Reading and writing files with proper error handling.

use std::fs::{self, File, OpenOptions};
use std::io::{self, BufRead, BufReader, Write};

fn read_lines(path: &str) -> io::Result<Vec<String>> {
    let file = File::open(path)?;
    let reader = BufReader::new(file);
    reader.lines().collect()
}

fn write_file(path: &str, content: &str) -> io::Result<()> {
    fs::write(path, content)
}

fn append_line(path: &str, line: &str) -> io::Result<()> {
    let mut file = OpenOptions::new()
        .create(true)
        .append(true)
        .open(path)?;
    writeln!(file, "{}", line)
}

fn main() -> io::Result<()> {
    // Write
    write_file("example.txt", "line one\nline two\n")?;

    // Append
    append_line("example.txt", "line three")?;

    // Read
    let lines = read_lines("example.txt")?;
    for (i, line) in lines.iter().enumerate() {
        println!("{}: {}", i + 1, line);
    }

    // Cleanup
    fs::remove_file("example.txt")?;
    Ok(())
}

HTTP Server (Blocking, Minimal)#

A tiny TCP-based HTTP server using only the standard library.

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

fn main() -> std::io::Result<()> {
    let listener = TcpListener::bind("127.0.0.1:8080")?;
    println!("Listening on http://127.0.0.1:8080");

    for stream in listener.incoming() {
        let mut stream = stream?;
        let mut buffer = [0u8; 1024];
        stream.read(&mut buffer)?;

        let request = String::from_utf8_lossy(&buffer);
        let path = request
            .lines()
            .next()
            .unwrap_or("")
            .split_whitespace()
            .nth(1)
            .unwrap_or("/");

        let (status, body) = match path {
            "/" => ("200 OK", "Hello, world!"),
            "/health" => ("200 OK", "ok"),
            _ => ("404 Not Found", "Not Found"),
        };

        let response = format!(
            "HTTP/1.1 {}\r\nContent-Length: {}\r\n\r\n{}",
            status,
            body.len(),
            body
        );
        stream.write_all(response.as_bytes())?;
    }
    Ok(())
}

Concurrency (Threads + Channels)#

Spawning threads and communicating with channels.

use std::sync::mpsc;
use std::thread;
use std::time::Duration;

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

    for id in 0..num_workers {
        let tx = tx.clone();
        thread::spawn(move || {
            let result = id * id;
            thread::sleep(Duration::from_millis(100));
            tx.send((id, result)).unwrap();
        });
    }

    // Drop the original sender so rx knows when all senders are gone
    drop(tx);

    for (id, result) in rx {
        println!("Worker {} produced: {}", id, result);
    }
    println!("All workers finished.");
}

Concurrency (Shared State with Arc + Mutex)#

Sharing mutable state across threads safely.

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

fn main() {
    let counter = Arc::new(Mutex::new(0u64));
    let mut handles = vec![];

    for _ in 0..10 {
        let counter = Arc::clone(&counter);
        let handle = thread::spawn(move || {
            for _ in 0..1000 {
                let mut num = counter.lock().unwrap();
                *num += 1;
            }
        });
        handles.push(handle);
    }

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

    println!("Final count: {}", *counter.lock().unwrap());
    // Always prints 10000
}

Error Handling Patterns#

Combining thiserror for library errors and ? propagation.

use std::fs;
use std::io;
use std::num::ParseIntError;

// Custom error enum (in a real project, use thiserror derive)
#[derive(Debug)]
enum AppError {
    Io(io::Error),
    Parse(ParseIntError),
    Validation(String),
}

impl std::fmt::Display for AppError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            AppError::Io(e) => write!(f, "IO error: {}", e),
            AppError::Parse(e) => write!(f, "Parse error: {}", e),
            AppError::Validation(msg) => write!(f, "Validation: {}", msg),
        }
    }
}

impl From<io::Error> for AppError {
    fn from(e: io::Error) -> Self { AppError::Io(e) }
}

impl From<ParseIntError> for AppError {
    fn from(e: ParseIntError) -> Self { AppError::Parse(e) }
}

fn read_age(path: &str) -> Result<u8, AppError> {
    let content = fs::read_to_string(path)?;           // io::Error -> AppError
    let age: u8 = content.trim().parse()?;              // ParseIntError -> AppError
    if age > 150 {
        return Err(AppError::Validation("age too high".to_string()));
    }
    Ok(age)
}

fn main() {
    match read_age("age.txt") {
        Ok(age) => println!("Age: {}", age),
        Err(e) => eprintln!("Failed: {}", e),
    }
}

Struct + Trait + Impl (Complete Example)#

Defining behavior through traits with multiple implementations.

trait Vehicle {
    fn drive(&self);
    fn stop(&self);
    fn fuel_type(&self) -> &'static str;
    fn wheels(&self) -> u8;
}

struct Car {
    fuel: &'static str,
    wheels: u8,
}

impl Vehicle for Car {
    fn drive(&self) { println!("The car is driving."); }
    fn stop(&self) { println!("The car stopped."); }
    fn fuel_type(&self) -> &'static str { self.fuel }
    fn wheels(&self) -> u8 { self.wheels }
}

struct Bike {
    wheels: u8,
}

impl Vehicle for Bike {
    fn drive(&self) { println!("The bike is being ridden."); }
    fn stop(&self) { println!("The bike stopped."); }
    fn fuel_type(&self) -> &'static str { "none" }
    fn wheels(&self) -> u8 { self.wheels }
}

fn describe(v: &dyn Vehicle) {
    v.drive();
    println!("  Fuel: {}, Wheels: {}", v.fuel_type(), v.wheels());
    v.stop();
}

fn main() {
    let car = Car { fuel: "gasoline", wheels: 4 };
    let bike = Bike { wheels: 2 };

    describe(&car);
    describe(&bike);
}

Iterator Chaining#

Practical examples of composing iterator adaptors.

fn main() {
    // Word frequency count
    let text = "the quick brown fox jumps over the lazy dog the fox";
    let mut freq = std::collections::HashMap::new();
    for word in text.split_whitespace() {
        *freq.entry(word).or_insert(0u32) += 1;
    }

    // Sort by frequency descending, then alphabetically
    let mut sorted: Vec<_> = freq.iter().collect();
    sorted.sort_by(|a, b| b.1.cmp(a.1).then(a.0.cmp(b.0)));

    for (word, count) in &sorted {
        println!("{:>4} {}", count, word);
    }

    // Pipeline: filter, transform, collect
    let numbers: Vec<i32> = (1..=20)
        .filter(|n| n % 3 == 0)
        .map(|n| n * n)
        .collect();
    println!("Squares of multiples of 3: {:?}", numbers);
}

Troubleshooting#

IssueCauseSolution
unused variable or unused import warningsDeclared but never usedPrefix with _ (e.g. _x) or remove the item
cannot find value in this scopeVariable declared in a different block or scopeMove the declaration to an enclosing scope or pass it as a parameter
mismatched types in match armsDifferent branches return different typesEnsure all arms return the same type, or use an enum to wrap variants
borrow of moved value in a loopValue consumed in first iterationClone, borrow with &, or restructure the loop
unused Result that must be usedIgnoring a Result return valueHandle with ?, match, or explicitly let _ = ... to suppress

See also#

Sources#