Memory Management Patterns

Rust’s ownership system influences how we manage resources:

RAII (Resource Acquisition Is Initialization)

RAII is a fundamental pattern in Rust where resources are acquired during initialization and released when the object goes out of scope:

struct File {
    handle: std::fs::File,
}

impl File {
    fn new(path: &str) -> Result<Self, std::io::Error> {
        let handle = std::fs::File::open(path)?;
        Ok(File { handle })
    }
    
    fn read_to_string(&mut self) -> Result<String, std::io::Error> {
        let mut content = String::new();
        self.handle.read_to_string(&mut content)?;
        Ok(content)
    }
}

// The file is automatically closed when `file` goes out of scope
fn process_file(path: &str) -> Result<String, std::io::Error> {
    let mut file = File::new(path)?;
    file.read_to_string()
}

Drop Guard

A drop guard ensures that cleanup code runs even if a function returns early:

struct CleanupGuard<F: FnMut()> {
    cleanup: F,
}

impl<F: FnMut()> Drop for CleanupGuard<F> {
    fn drop(&mut self) {
        (self.cleanup)();
    }
}

fn with_cleanup<F: FnMut()>(cleanup: F) -> CleanupGuard<F> {
    CleanupGuard { cleanup }
}

fn process_data() -> Result<(), std::io::Error> {
    // Set up some resource
    let resource = setup_resource()?;
    
    // Create a guard that will clean up the resource
    let _guard = with_cleanup(|| {
        cleanup_resource(&resource);
    });
    
    // Process the resource (may return early)
    if let Err(e) = process_resource(&resource) {
        return Err(e);
    }
    
    // More processing (may also return early)
    if let Err(e) = more_processing(&resource) {
        return Err(e);
    }
    
    // The guard will clean up the resource when it goes out of scope
    Ok(())
}

Scoped Operations

Scoped operations ensure that resources are properly managed within a specific scope:

use std::sync::{Mutex, MutexGuard};

struct Database {
    data: Mutex<Vec<String>>,
}

impl Database {
    fn new() -> Self {
        Database {
            data: Mutex::new(Vec::new()),
        }
    }
    
    // Returns a scoped guard that provides access to the data
    fn access(&self) -> Result<MutexGuard<Vec<String>>, std::sync::PoisonError<MutexGuard<Vec<String>>>> {
        self.data.lock()
    }
}

fn main() {
    let db = Database::new();
    
    // The scope ensures the lock is released when `data` goes out of scope
    {
        let mut data = db.access().unwrap();
        data.push("Hello".to_string());
        data.push("World".to_string());
        // Lock is automatically released here
    }
    
    // We can acquire the lock again
    {
        let data = db.access().unwrap();
        println!("Data: {:?}", *data);
    }
}

Creational Patterns

Patterns for object creation in Rust:

Builder Pattern

The builder pattern allows for flexible object construction with a fluent interface:

#[derive(Debug, Default)]
struct HttpRequest {
    method: String,
    url: String,
    headers: std::collections::HashMap<String, String>,
    body: Option<Vec<u8>>,
}

#[derive(Debug)]
struct HttpRequestBuilder {
    request: HttpRequest,
}

impl HttpRequestBuilder {
    fn new() -> Self {
        HttpRequestBuilder {
            request: HttpRequest::default(),
        }
    }
    
    fn method(mut self, method: impl Into<String>) -> Self {
        self.request.method = method.into();
        self
    }
    
    fn url(mut self, url: impl Into<String>) -> Self {
        self.request.url = url.into();
        self
    }
    
    fn header(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
        self.request.headers.insert(key.into(), value.into());
        self
    }
    
    fn body(mut self, body: impl Into<Vec<u8>>) -> Self {
        self.request.body = Some(body.into());
        self
    }
    
    fn build(self) -> HttpRequest {
        self.request
    }
}

fn main() {
    let request = HttpRequestBuilder::new()
        .method("GET")
        .url("https://example.com")
        .header("User-Agent", "Rust")
        .header("Accept", "text/html")
        .build();
    
    println!("{:?}", request);
}