Rust 1.95.0 ya está disponible como nueva versión estable del lenguaje, con cambios que apuntan a una mejora muy concreta: hacer más cómodo escribir código multiplataforma y reducir parte del ruido en expresiones match. No es una versión de ruptura ni una revolución del lenguaje, pero sí incorpora dos novedades que muchos desarrolladores notarán en el día a día: la macro cfg_select! y los if let guards dentro de match.
La actualización puede instalarse con el comando habitual si Rust se gestiona mediante rustup:
rustup update stable
Rust mantiene así su ritmo de evolución incremental, con una combinación de nuevas capacidades del lenguaje, APIs estabilizadas y pequeños ajustes en compilador, Cargo y Clippy. Para equipos que usan Rust en software de sistemas, herramientas CLI, backends, librerías multiplataforma o proyectos embebidos, la versión 1.95 merece atención porque simplifica casos que hasta ahora obligaban a usar crates auxiliares o estructuras menos limpias.
cfg_select!: compilación condicional con sintaxis nativa
La novedad más visible de Rust 1.95 es cfg_select!, una macro que actúa de forma parecida a un match en tiempo de compilación sobre condiciones cfg. Su objetivo es resolver una necesidad habitual: seleccionar código distinto según el sistema operativo, arquitectura, anchura de puntero o cualquier otro predicado de configuración.
Hasta ahora era muy común usar el crate cfg-if, muy popular en el ecosistema Rust, para escribir este tipo de lógica de forma más legible. Con cfg_select!, Rust incorpora una alternativa nativa, aunque con una sintaxis propia.
Ejemplo básico:
cfg_select! {
unix => {
fn platform_name() -> &'static str {
"Unix"
}
}
windows => {
fn platform_name() -> &'static str {
"Windows"
}
}
_ => {
fn platform_name() -> &'static str {
"Unknown"
}
}
}
La macro expande el bloque de la primera rama cuya condición sea verdadera. Si ninguna coincide, puede usarse _ como caso por defecto.
También puede devolver expresiones:
let platform = cfg_select! {
windows => "windows",
unix => "unix",
_ => "other",
};
println!("Running on {platform}");
Este tipo de construcción encaja muy bien en librerías multiplataforma, herramientas de línea de comandos y proyectos que necesitan compilar en Linux, macOS, Windows o entornos embebidos sin llenar el código de atributos #[cfg(...)] dispersos.
Antes |
Ahora con Rust 1.95 |
Uso frecuente de | Alternativa nativa con |
Atributos | Selección centralizada y más legible |
Más dependencia de crates auxiliares | Menos necesidad de dependencias para casos simples |
Código multiplataforma más difícil de seguir | Rama de compilación más parecida a un |
Esto no significa que cfg-if desaparezca de golpe. Muchos proyectos lo seguirán usando, bien por compatibilidad con versiones antiguas de Rust, bien porque ya forma parte de su base de código. Pero para proyectos nuevos que puedan exigir Rust 1.95 o superior, cfg_select! ofrece una vía limpia sin añadir una dependencia más.
if let guards en match: menos anidamiento y más claridad
La segunda mejora destacada está en las expresiones match. Rust 1.88 estabilizó las let chains, y Rust 1.95 lleva esa capacidad a los guards de match, permitiendo condiciones basadas en pattern matching dentro de una rama.
Antes, ciertos casos obligaban a combinar match con if anidados o a reorganizar la lógica en varias fases. Ahora puede escribirse algo así:
match value {
Some(x) if let Ok(y) = compute(x) => {
println!("x = {x}, y = {y}");
}
_ => {
println!("No valid value");
}
}
La ventaja es que tanto x como y están disponibles dentro del bloque de la rama. Esto permite expresar de forma más directa casos donde primero se cumple un patrón y después se necesita comprobar otro resultado.
Un ejemplo más cercano a código real:
fn parse_user_id(input: Option<&str>) {
match input {
Some(raw) if let Ok(id) = raw.parse::<u64>() => {
println!("Valid user id: {id}");
}
Some(raw) => {
println!("Invalid user id: {raw}");
}
None => {
println!("Missing user id");
}
}
}
Sin esta mejora, el código habría requerido un if let adicional dentro de la rama Some(raw) o una conversión previa. La nueva sintaxis reduce ruido y hace más natural combinar extracción de valores con validación.
Hay un matiz importante: el compilador no tiene en cuenta los patrones de los if let guards para evaluar la exhaustividad general del match, igual que ocurre con los guards if tradicionales. Por tanto, no conviene asumir que el compilador «entiende» esas ramas como cobertura completa de todos los casos posibles. Siguen siendo condiciones adicionales, no patrones principales del match.
APIs estabilizadas: pequeñas piezas para código más fino
Rust 1.95 también estabiliza un conjunto amplio de APIs. No todas tendrán impacto directo en cualquier aplicación, pero varias son relevantes para código de bajo nivel, estructuras de datos, concurrencia y optimización.
Entre las más interesantes están Vec::push_mut y Vec::insert_mut, que permiten insertar un elemento y obtener una referencia mutable al valor insertado. Esto puede ahorrar pasos cuando se quiere construir o modificar un elemento justo después de añadirlo al vector.
Ejemplo:
let mut users = Vec::new();
let user = users.push_mut(String::from("ana"));
user.push_str("@example.com");
assert_eq!(users[0], "[email protected]");
También llegan variantes similares para VecDeque y LinkedList, además de nuevas funciones update y try_update en tipos atómicos como AtomicPtr y AtomicBool. Estas operaciones ayudan a expresar actualizaciones atómicas de forma más directa en código concurrente.
Otra API destacada es core::hint::cold_path, una pista para marcar rutas de ejecución poco frecuentes. Puede ser útil en código muy sensible al rendimiento, por ejemplo para separar caminos de error de rutas calientes:
fn process(value: i32) -> i32 {
if value < 0 {
core::hint::cold_path();
return 0;
}
value * 2
}
No es una herramienta que deba usarse a ciegas. Las pistas al compilador tienen sentido cuando hay mediciones y una ruta realmente poco frecuente. Usarlas por intuición puede no aportar nada o incluso dificultar el mantenimiento.
API o cambio |
Para qué puede servir |
| Insertar y modificar un elemento sin búsquedas posteriores |
APIs similares en | Mejor ergonomía en colecciones |
| Actualizaciones atómicas más expresivas |
| Marcar rutas frías, como errores raros |
| Conversiones enteras a booleano más controladas |
Nuevas APIs en | Mejor soporte para código de bajo nivel y memoria no inicializada |
La estabilización de APIs alrededor de MaybeUninit, Cell y Layout apunta sobre todo a desarrolladores que trabajan cerca de la memoria, allocators, abstracciones de bajo nivel o librerías que necesitan controlar inicialización y disposición de datos con precisión.
Cambio importante: JSON target specs fuera de stable
Rust 1.95 elimina en estable el soporte para pasar una especificación de target personalizada en JSON a rustc. Según el equipo de Rust, esto no debería afectar a usuarios que trabajan con una toolchain completamente estable, porque construir la librería estándar, incluso solo core, ya requería funciones exclusivas de nightly.
Este cambio sí puede importar a equipos que mantienen targets personalizados, entornos embebidos, sistemas operativos experimentales o toolchains internas. En esos casos, probablemente ya estaban usando nightly, pero conviene revisar pipelines de compilación, scripts de CI y documentación técnica para evitar sorpresas.
La comunidad de Rust está recopilando casos de uso para estudiar si alguna forma de esta funcionalidad debería estabilizarse en el futuro. Es un punto sensible porque los targets personalizados son importantes para nichos muy técnicos, pero estabilizarlos implica compromisos de mantenimiento y compatibilidad a largo plazo.
Qué significa Rust 1.95 para desarrolladores
Rust 1.95 no cambia la forma de aprender el lenguaje, pero sí mejora la experiencia de quien ya mantiene proyectos reales. cfg_select! reduce dependencia de macros externas para compilación condicional. Los if let guards hacen que algunos match sean más expresivos. Las APIs estabilizadas aportan detalles útiles para colecciones, concurrencia y código de bajo nivel.
Para un backend o una herramienta CLI, las mejoras se notarán sobre todo en legibilidad. Para una librería multiplataforma, cfg_select! puede limpiar bastante código. Para un proyecto de sistemas, las nuevas APIs estabilizadas pueden reducir código unsafe o simplificar patrones que antes requerían rodeos.
Quienes mantengan librerías públicas deberán decidir si elevan su versión mínima soportada de Rust. No todos los proyectos pueden adoptar Rust 1.95 de inmediato, porque muchas crates intentan mantener compatibilidad con versiones anteriores. Pero incluso cuando no se use ya en producción, conviene conocer las novedades para planificar futuras limpiezas de código.
Rust sigue avanzando sin perder su prioridad: seguridad de memoria, rendimiento y control. Versiones como esta no hacen mucho ruido fuera de la comunidad, pero son las que van puliendo el lenguaje hasta hacerlo más cómodo para proyectos grandes. Menos anidamiento, menos dependencias auxiliares y mejores APIs pequeñas acaban marcando diferencia cuando una base de código crece.
Preguntas frecuentes
¿Cómo se actualiza a Rust 1.95?
Si usas rustup, basta con ejecutar rustup update stable en la terminal.
¿Qué es cfg_select!?
Es una macro estable que permite seleccionar código en tiempo de compilación según condiciones cfg, de forma parecida a un match.
¿cfg_select! sustituye al crate cfg-if?
Puede sustituirlo en muchos casos simples o nuevos proyectos, aunque cfg-if seguirá siendo útil en bases de código existentes o si se necesita compatibilidad con versiones antiguas de Rust.
¿Qué aportan los if let guards en match?
Permiten combinar un patrón principal con una condición adicional que también hace pattern matching, reduciendo anidamientos y mejorando la lectura.
