El tooling diario: rustfmt, clippy y rust-analyzer
Las tres herramientas que acompañan cada línea de Rust: rustfmt para el formato, clippy para aprender el idioma idiomático, y rust-analyzer como cerebro en tu editor. Por qué no son opcionales.
El compilador de Rust es exigente, pero no está solo. A su alrededor hay tres herramientas oficiales que convierten el ciclo de escritura en un diálogo constante: rustfmt decide el formato, clippy te enseña a escribir Rust idiomático, y rust-analyzer te da inteligencia semántica en vivo. No son adornos: son parte del lenguaje tal y como se usa de verdad.
- Formatear código de forma canónica con
rustfmt. - Aprender Rust idiomático a través de
clippy. - Entender qué aporta
rust-analyzercomo servidor LSP. - Integrar los tres en un único bucle de trabajo.
rustfmt: se acabaron los debates de estilo
rustfmt es el formateador oficial. Aplica un estilo canónico y no negociable, de modo que ningún equipo vuelve a discutir dónde van las llaves:
cargo fmt # formatea todo el paquete in situ
cargo fmt --check # no toca nada; falla si algo está sin formatear (ideal para CI)
Se puede afinar con un rustfmt.toml en la raíz, aunque la recomendación es tocar lo mínimo:
max_width = 100
edition = "2024"
El valor real no es la estética: es que el formato deja de ser una decisión. El diff de un commit muestra solo cambios de lógica, nunca de espaciado.
clippy: un profesor de Rust idiomático
clippy es el linter oficial, con más de 700 lints organizados por categorías: correctness (errores reales), style, complexity, perf, y el grupo pedantic que se activa aparte. Su verdadero valor no es cazar bugs, sino enseñarte a escribir como un rustáceo:
// Lo que escribe quien viene de otro lenguaje:
let mut cuadrados = Vec::new();
for x in &numeros {
cuadrados.push(x * x);
}
// Lo que clippy te sugiere: expresa la intención, no el bucle.
let cuadrados: Vec<_> = numeros.iter().map(|x| x * x).collect();
cargo clippy # analiza y sugiere
cargo clippy --fix # aplica las correcciones automáticas
cargo clippy -- -D warnings # en CI: cualquier lint es un error
Puedes silenciar un lint concreto con #[allow(clippy::nombre_del_lint)] cuando de verdad sabes lo que haces, pero la actitud sana es leer cada sugerencia como una lección.
Los grupos de lints se controlan a nivel de crate. Muchos proyectos suben el listón encendiendo pedantic y prohibiendo patrones peligrosos:
#![warn(clippy::pedantic)] // lints más estrictos, opcionales
#![deny(clippy::unwrap_used)] // prohíbe unwrap fuera de tests
Cada sugerencia de clippy enlaza a una explicación de por qué la forma idiomática es mejor. Leerlas durante tus primeras semanas de Rust equivale a un curso acelerado de estilo: aprendes los iteradores, el patrón if let, cuándo un match sobra y por qué clonar de más es un olor a código. Es tutoría gratuita en cada guardado.
rust-analyzer: el cerebro en tu editor
rust-analyzer es el servidor LSP oficial. Corre en segundo plano y le da a cualquier editor —VS Code, Neovim, Helix, Emacs— inteligencia semántica de Rust en tiempo real:
Tipos e inlay hints
Te muestra el tipo inferido de cada variable y los nombres de los parámetros, sin que escribas anotaciones.
Navegación
Ir a la definición, buscar usos y ver la jerarquía de llamadas al instante.
Asistencias
Refactors y code actions: implementar un trait, rellenar los brazos de un match, importar lo que falta.
Lentes de ejecución
Botones inline para correr o depurar un test justo encima de su fn.
Un ajuste que todo el mundo activa: que rust-analyzer use clippy al guardar, para tener sus lints en vivo dentro del editor.
{
"rust-analyzer.check.command": "clippy"
}
rust-analyzer no es un editor ni un plugin: es un proceso aparte que habla el protocolo LSP, así que el mismo cerebro sirve a VS Code, Neovim o Helix sin cambiar de motor. Comparte además el modelo de cargo, por lo que sus tipos y errores coinciden con los del compilador en vez de ser una aproximación.
El bucle completo
Las tres herramientas, junto al compilador, forman un ciclo cerrado que gira mientras escribes:
flowchart LR W[escribes codigo] --> A[rust-analyzer avisa en vivo] A --> F[cargo fmt formatea] F --> C[cargo clippy ensena idioms] C --> W
Ese bucle se automatiza. Puedes definir un alias de cargo que encadene formato, lints y tests en una sola orden, y ejecutar exactamente lo mismo en tu máquina y en CI:
[alias]
lint = "clippy --all-targets --all-features -- -D warnings"
verifica = "!cargo fmt --check && cargo lint && cargo test"
cargo verifica # formato + clippy estricto + tests, de un golpe
La regla de oro de un proyecto serio es que la CI corra cargo fmt --check y cargo clippy -- -D warnings: así ningún commit con formato torcido o con un lint sin resolver llega a la rama principal. Lo que en local es una ayuda, en CI es una garantía.
Si un lint de clippy te estorba de forma sistemática, la respuesta no es ignorarlo a mano una y otra vez, sino decidirlo explícitamente en clippy.toml o con un #![allow(...)] a nivel de crate, documentando por qué. Una configuración deliberada es señal de dominio; silenciar por fastidio es deuda técnica disfrazada.
Hay una diferencia enorme entre “sé la sintaxis de Rust” y “trabajo en Rust”, y buena parte de esa diferencia son estas tres herramientas. El compilador te dice qué está mal; clippy te dice qué está mediocre y cómo mejorarlo; rust-analyzer te lo dice antes de compilar, mientras el cursor sigue en la línea; y rustfmt borra del mapa toda una categoría de discusiones estériles. Juntos convierten Rust en un lenguaje que enseña activamente mientras lo usas: cada guardado es una mini-revisión de código hecha por un experto incansable. Quien desactiva clippy porque “molesta” o programa sin rust-analyzer porque “ya sé lo que hago” se está negando el mejor tutor disponible y, además, rechazando el flujo con el que trabaja el resto del ecosistema. Instalar estas herramientas el primer día no es preparar el entorno: es aceptar que en Rust la calidad del código no se revisa al final, se cultiva en cada tecla. Ese es el nivel profesional, y empieza aquí.
- Ejecuta
cargo fmtsobre un proyecto y mira el diff; luego pruebacargo fmt --check. - Escribe un bucle
forque llene unVecy deja quecargo clippyte sugiera la versión con iteradores. - Aplica una sugerencia automáticamente con
cargo clippy --fix. - Configura tu editor para usar rust-analyzer con
check.commandigual aclippy. - Pasa el cursor sobre una variable sin tipo anotado y confirma que rust-analyzer te muestra el tipo inferido.