Patrones de diseño en Rust con ejemplos de código

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course
```html

Patrones de diseño en Rust: guía práctica con ejemplos



Los patrones de diseño son soluciones probadas para problemas típicos de desarrollo. En Rust, gracias a su sistema único de ownership y modelo de memoria, la implementación de patrones clásicos a menudo difiere de los lenguajes con recolección de basura. En este artículo analizaremos tres patrones clave: Singleton, Builder y Strategy, adaptados a las particularidades de Rust.



1. Patrón Singleton en Rust: estado global sin unsafe



Singleton garantiza que una clase tiene una única instancia y proporciona un punto de acceso global a ella. En Rust, el crate once_cell o el estable std::sync::OnceLock (desde Rust 1.70) son ideales para esto.



Implementación con OnceLock

use std::sync::OnceLock;

pub struct Logger { level: String,}

impl Logger { pub fn global() -> &'static Logger { static INSTANCE: OnceLock<Logger> = OnceLock::new(); INSTANCE.get_or_init(|| Logger { level: "info".to_string(), }) }

pub fn log(&self, msg: &str) { println!("[{}] {}", self.level, msg); }}

fn main() { let logger = Logger::global(); logger.log("¡Hola, Rust!"); // Logger::global() devolverá la misma instancia}


Ventajas: Seguridad (sin unsafe), inicialización perezosa, seguridad en concurrencia. Desventaja: el estado global dificulta las pruebas.



2. Patrón Builder: construcción de objetos complejos



Builder separa la construcción de un objeto complejo de su representación. En Rust es especialmente útil para estructuras con múltiples campos opcionales.



Ejemplo: configuración de un cliente HTTP

pub struct HttpClient {    url: String,    timeout: u64,    headers: Vec<(String, String)>,}

pub struct HttpClientBuilder { url: String, timeout: Option<u64>, headers: Vec<(String, String)>,}

impl HttpClientBuilder { pub fn new(url: &str) -> Self { HttpClientBuilder { url: url.to_string(), timeout: None, headers: vec![], } }

pub fn timeout(mut self, secs: u64) -> Self { self.timeout = Some(secs); self }

pub fn header(mut self, key: &str, value: &str) -> Self { self.headers.push((key.to_string(), value.to_string())); self }

pub fn build(self) -> HttpClient { HttpClient { url: self.url, timeout: self.timeout.unwrap_or(30), headers: self.headers, } }}

fn main() { let client = HttpClientBuilder::new("https://api.example.com") .timeout(10) .header("Authorization", "Bearer token123") .build(); println!("URL del cliente: {}", client.url);}


Importante: Usar self (no &self) en los métodos del builder permite evitar clonaciones y hace la API más ergonómica.



3. Patrón Strategy: algoritmos como estrategias intercambiables



Strategy define una familia de algoritmos, encapsula cada uno de ellos y los hace intercambiables. En Rust esto se implementa mediante traits y despacho dinámico (Box<dyn Trait>).



Ejemplo: sistema de ordenamiento

trait SortStrategy {    fn sort(&self, data: &mut [i32]);}

struct BubbleSort;impl SortStrategy for BubbleSort { fn sort(&self, data: &mut [i32]) { let n = data.len(); for i in 0..n { for j in 0..n - i - 1 { if data[j] > data[j + 1] { data.swap(j, j + 1); } } } }}

struct QuickSort;impl SortStrategy for QuickSort { fn sort(&self, da ```

Blogs

Book Recommendations