Rust 1.75 y 1.76: mejoras que se notan en el día a día
Índice de contenidos
- Puntos clave
- Rust 1.75: async fn en traits
- Return-position impl Trait en traits
- Rust 1.75 también estabiliza: aritmética de punteros en bytes
- Rust 1.75 también trae: inlining automático entre crates
- Rust 1.76: compatibilidad ABI y utilidades de conveniencia
- Compatibilidad y actualización
- Conclusión
- Fuentes
Actualizado: 2026-07-12
Rust 1.75 estabiliza async fn en traits, el return-position impl Trait y varios métodos de punteros en bytes como byte_add. Rust 1.76 añade la garantía ABI entre char y u32, además de utilidades como Result::inspect y type_name_of_val. Dos releases que suman ergonomía real sin gestos vistosos.
Rust 1.75 (diciembre de 2023) y Rust 1.76 (febrero de 2024) son el tipo de releases que los desarrolladores agradecen en retrospectiva: sin titulares llamativos, pero con mejoras que se notan en el código real. El cambio más significativo llega en 1.75: la estabilización de async fn en traits, una limitación que llevaba años obligando a usar el crate async-trait, junto con return-position impl Trait in traits y una tanda de métodos de punteros en bytes. Rust 1.76 es una release más modesta que cierra huecos de ergonomía en la biblioteca estándar y formaliza una garantía de compatibilidad ABI. Juntas, dejan el código async y los sistemas de bajo nivel algo más limpios.
Puntos clave
-
async fnen traits ya es estable en Rust 1.75: se elimina la dependencia del crateasync-traitpara el caso sindyn. -
Return-position
impl Traiten traits completa el soporte de tipos de retorno opacos sin boxing. -
La misma release 1.75 estabiliza
pointer::byte_addy métodos relacionados para aritmética de punteros en bytes. -
Rust 1.76 garantiza que
charyu32son compatibles en la ABI, y añade utilidades de conveniencia comoResult::inspectytype_name_of_val. -
Ambas releases son aditivas: el código existente sigue compilando sin cambios, la migración es opcional y gradual.
Rust 1.75: async fn en traits
La imposibilidad de declarar async fn directamente en un trait era una de las limitaciones más frustrantes del ecosistema Rust para quien venía de otros lenguajes. La causa técnica es la que impuso el compromiso: las funciones async retornan un tipo opaco (impl Future) que puede variar en tamaño según la implementación, lo que rompe el modelo de traits del compilador para tipos de tamaño estático.
La solución estabilizada en 1.75 usa desugar implícito: el compilador convierte async fn en el trait en un associated future type automáticamente. Para el caso sin dyn, esto funciona sin boxing:
trait AsyncDatabase {
async fn query(&self, sql: &str) -> Result<Vec<Row>, DbError>;
async fn execute(&self, sql: &str) -> Result<u64, DbError>;
}
struct Postgres { /* ... */ }
impl AsyncDatabase for Postgres {
async fn query(&self, sql: &str) -> Result<Vec<Row>, DbError> {
// implementación concreta
todo!()
}
async fn execute(&self, sql: &str) -> Result<u64, DbError> {
todo!()
}
}
Antes de 1.75, esto requería #[async_trait] del crate homónimo, que hace boxing de los futuros y añade overhead de heap allocation en cada llamada. Para código de alto rendimiento, precisamente el caso de uso donde más se usa Rust, ese overhead era inaceptable.
La limitación que permanece: async fn en trait no funciona directamente con dyn Trait. Para dispatch dinámico con traits async, se sigue necesitando boxing explícito o el crate async-trait. Esto cubre la mayoría de los casos prácticos, pero no todos. El diseño completo, incluida esta limitación, está documentado en el anuncio oficial de async fn y RPIT en traits[1].
Return-position impl Trait en traits
La misma release completa otra pieza del puzzle: return-position impl Trait (RPIT) en definiciones de trait. Esto permite declarar funciones en traits que retornan tipos que implementan un trait, sin necesitar boxing o associated types explícitos:
trait Container {
fn iter(&self) -> impl Iterator<Item = i32>;
fn into_sorted(self) -> impl Iterator<Item = i32>
where
Self: Sized;
}
struct MyVec(Vec<i32>);
impl Container for MyVec {
fn iter(&self) -> impl Iterator<Item = i32> {
self.0.iter().copied()
}
fn into_sorted(self) -> impl Iterator<Item = i32>
where
Self: Sized,
{
let mut v = self.0;
v.sort();
v.into_iter()
}
}
Antes de 1.75, este patrón requería o bien un associated type explícito (más verboso) o boxing con Box<dyn Iterator<Item = i32>> (con overhead de heap y pérdida de zero-cost abstractions). Para código de sistemas que produce iteradores, parsers o adaptadores, este cambio elimina una categoría entera de boilerplate.
Rust 1.75 también estabiliza: aritmética de punteros en bytes
La misma release estabiliza pointer::byte_add[2], pointer::byte_sub, pointer::byte_offset y sus variantes wrapping_*. La diferencia con los métodos existentes (add, sub) es que los nuevos trabajan en bytes, no en múltiplos del tamaño del tipo apuntado:
let arr: [u32; 4] = [1, 2, 3, 4];
let ptr: *const u32 = arr.as_ptr();
// Antes: requería cast explícito a *const u8 y vuelta
let second_byte = unsafe {
(ptr as *const u8).add(1).read()
};
// Con 1.75: más directo y expresivo
let second_byte = unsafe {
ptr.byte_add(1).cast::<u8>().read()
};
Para código que implementa protocolos binarios, parsers de bajo nivel o manipulación de memoria no tipada, este cambio reduce la verbosidad y los cast intermedios que oscurecen la intención.
Rust 1.75 también trae: inlining automático entre crates
1.75 estabiliza además una mejora silenciosa del compilador: el inlining automático entre crates para funciones pequeñas. Antes, una función solo se inlineaba entre crates si el autor la marcaba de forma explícita con #[inline]. Ahora el compilador puede decidirlo por sí mismo para funciones pequeñas, sin ese aviso manual. El efecto no es una compilación más rápida, sino código generado más eficiente en tiempo de ejecución para dependencias que no habían anotado sus funciones. El detalle técnico está documentado en el registro de cambios de rustc[3].
Rust 1.76: compatibilidad ABI y utilidades de conveniencia
Rust 1.76 no trae cambios de lenguaje tan visibles como 1.75: el propio anuncio oficial[4] la describe como una release relativamente menor. Aun así, incluye piezas útiles del día a día.
Garantía de compatibilidad ABI: se formaliza que char y u32 tienen el mismo tamaño y alineación, y que ambos son compatibles en la ABI en firmas de función. Es una garantía que ya se cumplía en la práctica, pero ahora está documentada y es estable.
APIs de conveniencia en la biblioteca estándar: se estabilizan Arc::unwrap_or_clone y Rc::unwrap_or_clone (extraer el valor interior o clonarlo si hay más referencias), Result::inspect / Result::inspect_err y Option::inspect (efectos secundarios sin consumir el valor), y std::any::type_name_of_val (nombre del tipo de un valor en tiempo de ejecución, útil con closures o tipos opacos que no se pueden nombrar). También llegan ptr::from_ref, ptr::from_mut y ptr::addr_eq, y std::hash::{DefaultHasher, RandomState} pasan a estar disponibles fuera de std::collections::hash_map.
Un detalle pequeño pero práctico: la macro dbg!() ahora añade el número de columna además de la línea, lo que ayuda a identificar la llamada exacta cuando hay varias en una misma línea.
Ferris, el cangrejo naranja mascota de la comunidad Rust, símbolo del lenguaje cuyas versiones 1.75 y 1.76 completan el soporte de async fn en traits y añaden utilidades de conveniencia en la biblioteca estándar
Compatibilidad y actualización
El upgrade a 1.75 o 1.76 es suave si el proyecto sigue la edición 2021, que es prácticamente todos los proyectos nuevos. Los cambios de async fn en traits son aditivos: el código existente que usaba async-trait sigue compilando, y la migración puede hacerse de forma gradual. Las únicas advertencias relevantes son para traits muy complejos con dyn que ya usaban workarounds manuales. Para quien sigue de cerca las novedades del lenguaje, las novedades de la edición 2024 son el siguiente hito natural tras estas dos releases.
Para proyectos que también usan Rust en el contexto de edge computing industrial, donde evitar allocations en entornos embebidos es crítico, la estabilización de async fn en traits sigue siendo la pieza más relevante de las dos releases.
Conclusión
Rust 1.75 y 1.76 son un ejemplo de madurez del lenguaje: no añaden ideas nuevas, sino que completan compromisos pendientes. La estabilización de async fn en traits elimina una deuda técnica que el ecosistema llevaba pagando con el crate async-trait. Los métodos de punteros en bytes simplifican código de sistemas que antes requería casts manuales. Rust 1.76, más modesta, cierra huecos de ergonomía en la biblioteca estándar y formaliza una garantía de ABI que ya existía en la práctica. Actualizar a las dos juntas deja el código async y el código de bajo nivel de Rust algo más limpio, sin sorpresas de compatibilidad.
Versión en inglés: Rust 1.75 and 1.76: Improvements Noticeable Daily.
Fuentes:
- Announcing Rust 1.75.0 (Rust Blog)[5]
- Announcing
async fnand return-positionimpl Traitin traits (Rust Blog)[1] - Announcing Rust 1.76.0 (Rust Blog)[4]
pointer::byte_add(Rust standard library docs)[2]- rust-lang/rust RELEASES.md (changelog)[3]