Toggle theme

Rust Snippets

Modern Rust programming patterns and features

Ownership and Borrowing

rust

Rust's memory safety principles

fn main() {
    // Ownership
    let s1 = String::from("hello");
    let s2 = s1;  // s1 is moved to s2
    // println!("{}", s1);  // Error: s1 is moved
    println!("{}", s2);  // OK

    // Borrowing
    let s3 = String::from("world");
    print_string(&s3);  // Immutable borrow
    println!("{}", s3);  // OK: s3 is still valid

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

fn print_string(s: &String) {
    println!("{}", s);
}

fn change_string(s: &mut String) {
    s.push_str(", world");
}

Traits and Generics

rust

Rust's approach to polymorphism

// Define a trait
trait Animal {
    fn make_sound(&self) -> String;
    fn get_name(&self) -> &str;
}

// Implement for specific types
struct Dog {
    name: String
}

impl Animal for Dog {
    fn make_sound(&self) -> String {
        String::from("Woof!")
    }

    fn get_name(&self) -> &str {
        &self.name
    }
}

struct Cat {
    name: String
}

impl Animal for Cat {
    fn make_sound(&self) -> String {
        String::from("Meow!")
    }

    fn get_name(&self) -> &str {
        &self.name
    }
}

// Generic function using trait bounds
fn animal_sounds<T: Animal>(animal: &T) {
    println!("{} says {}",
        animal.get_name(),
        animal.make_sound()
    );
}

fn main() {
    let dog = Dog { name: String::from("Rover") };
    let cat = Cat { name: String::from("Whiskers") };

    animal_sounds(&dog);
    animal_sounds(&cat);
}

Error Handling

rust

Result and Option types

use std::fs::File;
use std::io::{self, Read};

// Using Result for fallible operations
fn read_file(path: &str) -> Result<String, io::Error> {
    let mut file = File::open(path)?;
    let mut content = String::new();
    file.read_to_string(&mut content)?;
    Ok(content)
}

// Using Option for nullable values
fn find_user(id: u32) -> Option<User> {
    if id == 0 {
        None
    } else {
        Some(User { id })
    }
}

fn main() -> Result<(), io::Error> {
    // Using ? operator with Result
    let content = read_file("example.txt")?;
    println!("{}", content);

    // Pattern matching with Option
    match find_user(1) {
        Some(user) => println!("Found user {}", user.id),
        None => println!("User not found")
    }

    // Using combinators
    let user_id = find_user(2)
        .map(|user| user.id)
        .unwrap_or(0);

    Ok(())
}

Concurrency

rust

Safe concurrent programming

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

// Shared state between threads
fn shared_state() {
    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());
}

// Message passing between threads
use std::sync::mpsc;

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

    thread::spawn(move || {
        let val = String::from("hello");
        tx.send(val).unwrap();
    });

    let received = rx.recv().unwrap();
    println!("Got: {}", received);
}