Código limpio en Rust: principios, modismos y ejemplos prácticos

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

Introducción: Por qué el Código Limpio en Rust No es Solo un Estilo



Rust es un lenguaje que combina el rendimiento de C++ con la seguridad de memoria, pero su sistema único de propiedad y préstamo requiere un enfoque especial para escribir código. Los principios de Código Limpio formulados por Robert Martin adquieren una nueva dimensión en Rust: aquí, la limpieza del código está directamente vinculada con la corrección, el rendimiento y la mantenibilidad.



En este artículo, exploraremos cómo aplicar los modismos de Rust para crear código autodocumentado, seguro y eficiente. Verás cómo reemplazar errores típicos de principiantes con soluciones elegantes aceptadas en la comunidad de Rust.



1. Manejo de Errores Idiomático: De unwrap() a Patrones Expresivos



Uno de los primeros problemas que enfrentan los principiantes es el uso excesivo de unwrap(). En Código Limpio, un error no es una excepción, sino una parte de la arquitectura. Rust proporciona tipos Option y Result potentes para el manejo explícito de casos límite.



Ejemplo Incorrecto (Código Sucio)

fn parse_number(input: &str) -> i32 {    input.parse::<i32>().unwrap()}

fn main() { let val = parse_number("not a number"); println!("{}", val); // ¡Pánico!}


Ejemplo Correcto (Código Limpio)

use std::num::ParseIntError;

fn parse_number(input: &str) -> Result<i32, ParseIntError> { input.parse::<i32>()}

fn main() { match parse_number("42") { Ok(n) => println!("Número: {}", n), Err(e) => eprintln!("Error: {}", e), }}


¿Por qué esto es Código Limpio? La función declara explícitamente que puede fallar. El código que la llama decide cómo manejar el fallo — registrarlo, reintentarlo o propagar el error hacia arriba.



Técnica Avanzada: El Operador ?

fn read_config(path: &str) -> Result<String, std::io::Error> {    let content = std::fs::read_to_string(path)?;    Ok(content)}


El operador ? es un reemplazo elegante para las expresiones match verbosas. Retorna el error hacia arriba si el resultado es Err, y extrae el valor si es Ok. Esto reduce el anidamiento y mejora la legibilidad.



2. Propiedad y Préstamo: Diseña la Arquitectura, No Pelees con el Compilador



El sistema de propiedad de Rust puede parecer una limitación, pero en realidad ayuda a escribir código limpio. Los problemas comienzan cuando un desarrollador intenta "engañar" al compilador con clone() o Rc<RefCell> sin necesidad.



Anti-patrón: Clonación Excesiva

fn process_data(data: Vec<String>) {    for item in data.clone() { // ¿Por qué clonar?        println!("{}", item);    }    // data ya no se usa}


Solución Limpia: Préstamo por Referencia

fn process_data(data: &[String]) {    for item in data {        println!("{}", item);    }}

fn main() { let my_data = vec!["a".to_string(), "b".to_string()]; process_data(&my_data); // La propiedad se queda en main println!("El vector sigue accesible: {:?}", my_data);}


Principio de Código Limpio: Ámbito mínimo para mutaciones. Si una función no debe modificar datos — acepta una referencia inmutable &T. Si se necesita modificación — &mut T. Esto hace que el código sea predecible y seguro.



Modismo: Pasar la Propiedad para Transformación

fn to_uppercase(mut text: String) -> String {    text.make_ascii_uppercase();    text // La propiedad es retornada}


Aquí, la función "consume" el string, lo modifica y lo devuelve. Esto es eficiente (sin copias) y explícito: quien llama entiende que la variable original ya no es válida.



3. Closures y Funcional

Blogs

Book Recommendations