Por qué el código limpio en Rust no es un lujo, sino una necesidad
\n\nRust es un lenguaje que exige disciplina al desarrollador. El compilador aquí es estricto, pero justo: no perdona el descuido con la memoria, pero a cambio ofrece una velocidad y seguridad increíbles. Sin embargo, para realmente liberar el potencial de Rust, no basta con hacer que el código compile. Es necesario escribir código limpio — comprensible, mantenible y elegante.
\n\nEn este artículo, analizaremos cómo escribir código limpio en Rust para que tu proyecto no se convierta en un laberinto de bloques unsafe y genéricos enredados. Aprenderás sobre principios de nomenclatura, modismos de gestión de propiedad, manejo de errores y estructuración del código. ¡Vamos allá!
\n\n1. Nomenclatura: habla el idioma de Rust
\n\nUna nomenclatura correcta es la mitad del éxito. En Rust existen convenciones estrictas, y violarlas se percibe como un trapo rojo para un toro (especialmente en las revisiones de código).
\n\nReglas básicas
\n- \n
- snake_case para variables, funciones, métodos y módulos. \n
- PascalCase para tipos (struct, enum, trait). \n
- SCREAMING_SNAKE_CASE para constantes y variables estáticas. \n
Ejemplo:
\n\n// Malo\nlet UserName = "Alice";\nfn GetUserData() {}\nconst MAX_SIZE: u32 = 100;\n\n// Bueno\nlet user_name = "Alice";\nfn get_user_data() {}\nconst MAX_SIZE: u32 = 100;\n\nEvita abreviaturas (a menos que sean obvias)
\nEn lugar de calc_avg() es mejor escribir calculate_average(). En lugar de tmp — temp_buffer. Rust fomenta la legibilidad, no la brevedad.
Consejo: si escribes una función que acepta un closure, usa los nombres f, g o closure — es una práctica comúnmente aceptada.
2. Propiedad y préstamo: hazte amigo del compilador
\n\nEl sistema de propiedad es el corazón de Rust. El código limpio respeta las reglas de ownership y borrowing, sin intentar evitarlas mediante clone() o Rc innecesariamente.
Regla: prefiere el préstamo a la propiedad
\nSi una función no debe tomar posesión, acepta una referencia &T o una referencia mutable &mut T.
// Malo: clone innecesario\nfn process(data: Vec<i32>) {\n let mut sum = 0;\n for &val in &data {\n sum += val;\n }\n println!("Sum: {}", sum);\n}\n\n// Bueno: préstamo\nfn process(data: &[i32]) {\n let mut sum = 0;\n for &val in data {\n sum += val;\n }\n println!("Sum: {}", sum);\n}\n\nEvita la clonación excesiva
\nSi necesitas pasar datos a varios lugares, usa Rc (para escenarios de un solo hilo) o Arc (para múltiples hilos). Pero no abuses: para casos simples, las referencias son suficientes.
3. Manejo de errores: abandona el pánico
\n\nEn Rust hay dos formas principales de manejar errores: panic! (error irrecuperable) y Result<T, E> (recuperable). El código limpio usa Result siempre que sea posible. El pánico es el último recurso para situaciones verdaderamente excepcionales (por ejemplo, división por cero).
Usa el operador ?
\nEs una forma concisa de propagar el error hacia arriba. En lugar de engorrosos match, escribe:
use std::fs::File;\nuse std::io::Read;\n\nfn read_file(path: &str) -> Result<String, std::io::Error> {\n let mut file = File::open(path)?;\n let mut contents = String::new();\n file.read_to_string(&mut contents)?;\n Ok(contents)\n}\n\nCrea tus propios tipos de error
\nEn lugar de usar String como error, define una enumeración:
#[derive(Debug)]\nenum MyError {\n Io(std::io::Error),\n Parse(std::num::ParseIntError),\n}\n\nimpl From<std::io::Error> for My