thecodex.expert · The Codex Family of Knowledge
Snippets

Rust Snippets

13 idiomatic Rust patterns — copy, paste, adapt.

Rust 2024 edition 13 snippets Verified
Rustownership.rs
Ownership, borrowing, and clone
fn main() {
    // Move: String assignment transfers ownership
    let s1 = String::from("hello");
    let s2 = s1;            // s1 is MOVED — no longer valid
    // println!("{}", s1);  // ERROR: value borrowed after move
    println!("{}", s2);     // "hello"

    // Clone: explicit deep copy — both are valid
    let s3 = s2.clone();
    println!("{} {}", s2, s3);  // "hello hello"

    // Copy types (primitives) are copied silently
    let x = 42;
    let y = x;   // x is copied, not moved
    println!("{} {}", x, y);  // both valid

    // Borrowing: reference without taking ownership
    let s4 = String::from("world");
    let len = calculate_length(&s4);  // pass reference
    println!("{} has length {}", s4, len);  // s4 still valid

    // Mutable borrow
    let mut s5 = String::from("hello");
    change(&mut s5);
    println!("{}", s5);  // "hello, world"
}

fn calculate_length(s: &String) -> usize {
    s.len()  // borrows but doesn't take ownership
}

fn change(s: &mut String) {
    s.push_str(", world");
}
Rusterror_handling.rs
Error handling with ? operator and thiserror
use std::fs;
use std::num::ParseIntError;

// Custom error with thiserror (add to Cargo.toml: thiserror = "1")
// #[derive(Debug, thiserror::Error)]
// enum AppError {
//     #[error("IO error: {0}")]
//     Io(#[from] std::io::Error),
//     #[error("Parse error: {0}")]
//     Parse(#[from] ParseIntError),
// }

// Manual custom error
#[derive(Debug)]
enum AppError {
    Io(std::io::Error),
    Parse(ParseIntError),
}

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: {}", e),
            AppError::Parse(e) => write!(f, "Parse: {}", e),
        }
    }
}
impl From<std::io::Error> for AppError { fn from(e: std::io::Error) -> Self { AppError::Io(e) } }
impl From<ParseIntError> for AppError  { fn from(e: ParseIntError) -> Self { AppError::Parse(e) } }

// ? operator: return Err(e.into()) on failure
fn read_number_from_file(path: &str) -> Result<i32, AppError> {
    let content = fs::read_to_string(path)?;  // ? converts io::Error via From
    let num = content.trim().parse::<i32>()?;  // ? converts ParseIntError
    Ok(num)
}

fn main() {
    match read_number_from_file("number.txt") {
        Ok(n)  => println!("Number: {}", n),
        Err(e) => eprintln!("Error: {}", e),
    }
}
Rustiterators.rs
Iterator chains: map, filter, collect
fn main() {
    let nums = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

    // Lazy chain: nothing computed until collect()
    let result: Vec<i32> = nums.iter()
        .filter(|&&x| x % 2 == 0)   // keep evens
        .map(|&x| x * x)            // square
        .collect();
    println!("{:?}", result);  // [4, 16, 36, 64, 100]

    // Sum, product, count
    let sum: i32 = nums.iter().sum();
    let evens = nums.iter().filter(|&&x| x % 2 == 0).count();
    println!("sum={} evens={}", sum, evens);  // sum=55 evens=5

    // flat_map: flatten one level
    let words = vec!["hello world", "foo bar"];
    let all_words: Vec<&str> = words.iter()
        .flat_map(|s| s.split_whitespace())
        .collect();
    println!("{:?}", all_words);  // ["hello", "world", "foo", "bar"]

    // zip: combine two iterators
    let names = vec!["Alice", "Bob", "Carol"];
    let scores = vec![95, 87, 92];
    let paired: Vec<_> = names.iter().zip(scores.iter()).collect();
    println!("{:?}", paired);  // [("Alice", 95), ("Bob", 87), ("Carol", 92)]

    // take_while, skip_while
    let until_big: Vec<_> = nums.iter().take_while(|&&x| x < 5).collect();
    // [1, 2, 3, 4]

    // chain: concatenate iterators
    let a = vec![1, 2, 3];
    let b = vec![4, 5, 6];
    let combined: Vec<_> = a.iter().chain(b.iter()).collect();
}
Rustenums_match.rs
Enums, pattern matching, and if let
// Enum with associated data — like a tagged union
#[derive(Debug)]
enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(u8, u8, u8),
}

fn process(msg: Message) -> String {
    match msg {
        Message::Quit               => String::from("Quit"),
        Message::Move { x, y }     => format!("Move to ({}, {})", x, y),
        Message::Write(text)        => format!("Write: {}", text),
        Message::ChangeColor(r,g,b) => format!("Color: rgb({},{},{})", r, g, b),
        // match is exhaustive — compiler requires all variants
    }
}

fn main() {
    println!("{}", process(Message::Move { x: 10, y: 20 }));
    println!("{}", process(Message::Write(String::from("hello"))));

    // Option: Some(T) or None — Rust's null-safe type
    let maybe: Option<i32> = Some(42);

    // if let: extract if matches — avoids full match
    if let Some(n) = maybe {
        println!("Got: {}", n);
    }

    // while let
    let mut stack = vec![1, 2, 3];
    while let Some(top) = stack.pop() {
        println!("{}", top);  // 3, 2, 1
    }

    // Match guard: extra condition
    let n = 7;
    let desc = match n {
        x if x < 0   => "negative",
        0             => "zero",
        x if x % 2 == 0 => "positive even",
        _             => "positive odd",
    };
    println!("{}", desc);  // positive odd

    // Binding with @
    let msg = match n {
        x @ 1..=10 => format!("1-10: got {}", x),
        _          => String::from("other"),
    };
}
Rusttraits.rs
Traits, default implementations, and trait objects
use std::fmt;

trait Animal {
    fn name(&self) -> &str;
    fn speak(&self) -> String;
    // Default implementation
    fn describe(&self) -> String {
        format!("{} says: {}", self.name(), self.speak())
    }
}

struct Dog { name: String }
struct Cat { name: String }

impl Animal for Dog {
    fn name(&self) -> &str { &self.name }
    fn speak(&self) -> String { String::from("Woof!") }
}

impl Animal for Cat {
    fn name(&self) -> &str { &self.name }
    fn speak(&self) -> String { String::from("Meow!") }
    fn describe(&self) -> String {
        format!("{} silently judges you", self.name())  // override default
    }
}

// Generic: T must implement Animal — static dispatch (monomorphised)
fn print_animal<T: Animal>(a: &T) { println!("{}", a.describe()); }

// Trait object: dynamic dispatch — heterogeneous collection
fn loudest(animals: &[Box<dyn Animal>]) -> &dyn Animal {
    animals.iter()
        .max_by_key(|a| a.speak().len())
        .map(|a| a.as_ref())
        .unwrap()
}

fn main() {
    let animals: Vec<Box<dyn Animal>> = vec![
        Box::new(Dog { name: String::from("Rex") }),
        Box::new(Cat { name: String::from("Whiskers") }),
    ];
    for a in &animals { println!("{}", a.describe()); }
}
Rustclosures.rs
Closures: Fn, FnMut, FnOnce
fn apply<F: Fn(i32) -> i32>(f: F, x: i32) -> i32 { f(x) }
fn apply_mut<F: FnMut() -> i32>(mut f: F) -> i32 { f() }
fn apply_once<F: FnOnce() -> String>(f: F) -> String { f() }

fn make_adder(n: i32) -> impl Fn(i32) -> i32 {
    move |x| x + n  // move: capture n by value into the closure
}

fn main() {
    let double = |x| x * 2;
    println!("{}", apply(double, 5));   // 10
    println!("{}", apply(|x| x + 1, 10));  // 11

    // FnMut: closure that mutates captured state
    let mut count = 0;
    let mut counter = || { count += 1; count };
    println!("{}", apply_mut(&mut counter));  // 1
    println!("{}", apply_mut(&mut counter));  // 2

    // FnOnce: consumes captured values — can only be called once
    let name = String::from("Alice");
    let greet = move || format!("Hello, {}!", name);  // name moved into closure
    println!("{}", apply_once(greet));  // "Hello, Alice!"
    // println!("{}", name);  // ERROR: name was moved

    // Returning closures
    let add5 = make_adder(5);
    let add10 = make_adder(10);
    println!("{} {}", add5(3), add10(3));  // 8, 13

    // Closure as iterator adapter
    let threshold = 3;
    let filtered: Vec<_> = (1..=10)
        .filter(|&x| x > threshold)  // captures threshold
        .collect();
}
Ruststructs_impl.rs
Structs, impl blocks, and derive macros
#[derive(Debug, Clone, PartialEq)]  // auto-implement common traits
struct Rectangle {
    width: f64,
    height: f64,
}

impl Rectangle {
    // Associated function (static method) — constructor
    fn new(width: f64, height: f64) -> Self {
        assert!(width > 0.0 && height > 0.0, "dimensions must be positive");
        Rectangle { width, height }
    }

    fn square(size: f64) -> Self { Rectangle::new(size, size) }

    // Method: takes &self (immutable borrow)
    fn area(&self) -> f64 { self.width * self.height }
    fn perimeter(&self) -> f64 { 2.0 * (self.width + self.height) }
    fn is_square(&self) -> bool { self.width == self.height }

    // Mutable method: takes &mut self
    fn scale(&mut self, factor: f64) {
        self.width  *= factor;
        self.height *= factor;
    }
}

// Implement Display trait
impl std::fmt::Display for Rectangle {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}x{}", self.width, self.height)
    }
}

fn main() {
    let mut r = Rectangle::new(4.0, 6.0);
    println!("area: {}", r.area());      // 24
    println!("rect: {}", r);             // 4x6 (Display)
    println!("debug: {:?}", r);          // Rectangle { width: 4.0, height: 6.0 }

    r.scale(2.0);
    println!("scaled: {}", r);           // 8x12

    let sq = Rectangle::square(5.0);
    println!("is_square: {}", sq.is_square());  // true
}
Rustsmart_pointers.rs
Box, Rc, Arc, and interior mutability
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use std::cell::RefCell;

fn main() {
    // Box<T>: heap allocation — use for recursive types or large values
    let boxed = Box::new(42);
    println!("{}", *boxed);  // 42

    // Recursive type: without Box, size would be infinite
    #[derive(Debug)]
    enum List { Cons(i32, Box<List>), Nil }
    let list = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil))));

    // Rc<T>: shared ownership (single-threaded)
    let a = Rc::new(String::from("shared"));
    let b = Rc::clone(&a);   // increment ref count — no copy
    let c = Rc::clone(&a);
    println!("count: {}", Rc::strong_count(&a));  // 3
    // a dropped — count decremented; freed when count reaches 0

    // RefCell<T>: interior mutability — runtime borrow checking
    let shared = Rc::new(RefCell::new(vec![1, 2, 3]));
    let shared2 = Rc::clone(&shared);
    shared.borrow_mut().push(4);  // mutable borrow checked at runtime
    println!("{:?}", shared2.borrow());  // [1, 2, 3, 4]

    // Arc<T>: shared ownership across threads (atomic ref count)
    let arc = Arc::new(Mutex::new(0));
    let arc2 = Arc::clone(&arc);
    std::thread::spawn(move || {
        let mut n = arc2.lock().unwrap();
        *n += 1;
    }).join().unwrap();
    println!("{}", *arc.lock().unwrap());  // 1
}
Rustgenerics_traits.rs
Generics with trait bounds and where clauses
use std::fmt::Display;

// Multiple trait bounds: T must be Display and PartialOrd
fn largest<T: PartialOrd + Display>(list: &[T]) -> &T {
    let mut biggest = &list[0];
    for item in list {
        if item > biggest { biggest = item; }
    }
    biggest
}

// where clause: cleaner for complex bounds
fn print_pair<T, U>(a: T, b: U)
where
    T: Display + Clone,
    U: Display + std::fmt::Debug,
{
    println!("({}, {:?})", a, b);
}

// Generic struct with trait bound
struct Wrapper<T: Display> {
    value: T,
}

impl<T: Display> Wrapper<T> {
    fn show(&self) { println!("value: {}", self.value); }
}

// impl Trait: shorthand for generic in function signatures
fn make_greeting(name: impl Display) -> String {
    format!("Hello, {}!", name)
}

fn apply<T, F: Fn(T) -> T>(val: T, f: F) -> T { f(val) }

fn main() {
    let numbers = vec![34, 50, 25, 100, 65];
    println!("largest: {}", largest(&numbers));  // 100

    let words = vec!["apple", "fig", "banana"];
    println!("largest: {}", largest(&words));    // fig

    let w = Wrapper { value: 42 };
    w.show();  // value: 42

    println!("{}", make_greeting("Alice"));
    println!("{}", apply(5, |x| x * x));  // 25
}
Rustcollections.rs
HashMap, Vec patterns, and entry API
use std::collections::HashMap;

fn main() {
    // Vec: dynamic array
    let mut v: Vec<i32> = Vec::new();
    v.push(1); v.push(2); v.push(3);

    // Iterate
    for n in &v { print!("{} ", n); }
    println!();

    // Slices
    let slice = &v[1..];   // [2, 3]
    println!("{:?}", slice);

    // HashMap
    let mut scores: HashMap<String, i32> = HashMap::new();
    scores.insert(String::from("Alice"), 95);
    scores.insert(String::from("Bob"), 87);

    // entry API: insert only if missing
    scores.entry(String::from("Carol")).or_insert(90);
    scores.entry(String::from("Alice")).or_insert(0);  // not updated — Alice exists
    println!("{:?}", scores.get("Alice"));  // Some(95)

    // entry + modify
    let text = "hello world wonderful world";
    let mut word_count: HashMap<&str, u32> = HashMap::new();
    for word in text.split_whitespace() {
        let count = word_count.entry(word).or_insert(0);
        *count += 1;  // dereference to modify
    }
    println!("{:?}", word_count);  // {hello:1, world:2, wonderful:1}

    // Collecting into HashMap
    let pairs = vec![("a", 1), ("b", 2), ("c", 3)];
    let map: HashMap<&str, i32> = pairs.into_iter().collect();
}
Rustlifetimes.rs
Lifetime annotations
// Lifetime annotation: 'a says the return ref lives at least as long as both inputs
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() { x } else { y }
}

// Struct with a reference field — must annotate lifetime
struct Important<'a> {
    content: &'a str,  // content must outlive Important
}

impl<'a> Important<'a> {
    fn announce(&self) -> &str {
        self.content  // lifetime elision: returns 'a implicitly
    }
}

// 'static: lives for the entire program duration
// String literals are 'static
fn get_greeting() -> &'static str { "Hello!" }

fn main() {
    let s1 = String::from("long string");
    let result;
    {
        let s2 = String::from("xyz");
        result = longest(s1.as_str(), s2.as_str());
        println!("longest: {}", result);  // OK — s2 still alive
    }
    // println!("{}", result);  // ERROR — s2 dropped, result would dangle

    let novel = String::from("Call me Ishmael. Some years ago...");
    let first_sentence = novel.split('.').next().expect("Could not find a '.'");
    let imp = Important { content: first_sentence };
    println!("{}", imp.announce());
}
Rustasync_rust.rs
Async/await with Tokio
// Cargo.toml: tokio = { version = "1", features = ["full"] }
use tokio::time::{sleep, Duration};

async fn fetch_data(id: u32) -> String {
    sleep(Duration::from_millis(100)).await;  // non-blocking sleep
    format!("data-{}", id)
}

async fn sequential() {
    // Awaited in sequence — total ~200ms
    let a = fetch_data(1).await;
    let b = fetch_data(2).await;
    println!("sequential: {} {}", a, b);
}

async fn concurrent() {
    // join!: run concurrently — total ~100ms (parallel)
    let (a, b) = tokio::join!(
        fetch_data(1),
        fetch_data(2),
    );
    println!("concurrent: {} {}", a, b);
}

// Spawn: run a task on the runtime
async fn with_spawn() {
    let handle = tokio::spawn(async {
        fetch_data(99).await
    });
    let result = handle.await.unwrap();  // join the task
    println!("spawned: {}", result);
}

#[tokio::main]
async fn main() {
    sequential().await;
    concurrent().await;
    with_spawn().await;
}
Rustserde_json.rs
Serialisation with serde
// Cargo.toml:
// serde = { version = "1", features = ["derive"] }
// serde_json = "1"

use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
struct User {
    id: u32,
    name: String,
    email: String,
    #[serde(skip_serializing_if = "Option::is_none")]  // omit if None
    age: Option<u32>,
    #[serde(rename = "is_active")]  // rename field in JSON
    active: bool,
}

fn main() -> Result<(), serde_json::Error> {
    let user = User {
        id: 1,
        name: String::from("Alice"),
        email: String::from("alice@example.com"),
        age: Some(30),
        active: true,
    };

    // Serialize to JSON string
    let json = serde_json::to_string(&user)?;
    println!("{}", json);
    // {"id":1,"name":"Alice","email":"alice@example.com","age":30,"is_active":true}

    // Pretty print
    let pretty = serde_json::to_string_pretty(&user)?;
    println!("{}", pretty);

    // Deserialize from JSON
    let raw = r#"{"id":2,"name":"Bob","email":"bob@b.com","is_active":false}"#;
    let user2: User = serde_json::from_str(raw)?;
    println!("{:?}", user2);  // age is None (absent in JSON)

    // Deserialize to Value (unknown schema)
    let v: serde_json::Value = serde_json::from_str(raw)?;
    println!("{}", v["name"]);  // "Bob"

    Ok(())
}
Rust referenceRust overview · Learn Rust
← Go All Snippets →
Everything Rust in one place — learning paths, reference, playground, and more. Rust Hub →