Programación reactiva en Rust: bibliotecas, frameworks 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

Programación reactiva en Rust: descripción general de herramientas y ejemplos de código



La programación reactiva es un paradigma orientado a flujos de datos asíncronos y la propagación de cambios. En el ecosistema de Rust, se implementa a través de potentes bibliotecas como RxRust (Reactive Extensions), futures-rs y async-std. Estas herramientas permiten construir sistemas elegantes, tolerantes a fallos y de alto rendimiento, desde aplicaciones GUI hasta servicios de red. En este artículo, analizaremos los conceptos clave, mostraremos ejemplos prácticos y ayudaremos a elegir la biblioteca adecuada para su proyecto en Rust.



Bibliotecas principales para programación reactiva en Rust



Las bibliotecas más populares para programación reactiva en Rust incluyen:

  • RxRust — puerto de ReactiveX (Rx). Proporciona Observable, Observer, operadores map, filter, merge y otros. Ideal para el manejo de eventos y flujos de datos.
  • futures-rs — biblioteca base para cómputo asíncrono. Incluye Stream, Future, Sink. Es la base de muchos sistemas reactivos.
  • async-std — biblioteca estándar asíncrona. Proporciona versiones async de E/S de archivos, operaciones de red y canales (channels) para flujos reactivos.
  • tokio — runtime asíncrono con soporte para multiproceso. A menudo se usa junto con futures-rs para construir aplicaciones de red reactivas.


Ejemplo 1: Uso de RxRust para el manejo de eventos

RxRust permite crear Observables a partir de iteradores, eventos o fuentes asíncronas. A continuación, un ejemplo simple de generación de números, filtrado y suscripción al flujo:



use rxrust::prelude::*;

fn main() { // Creamos un Observable a partir de un rango de números observable::from_iter(1..10) .filter(|x| x % 2 == 0) // Dejamos solo los pares .map(|x| x * 10) // Multiplicamos por 10 .subscribe( |x| println!("Recibido: {}", x), |err| eprintln!("Error: {}", err), || println!("Flujo completado"), );}


Resultado de la ejecución:

Recibido: 20Recibido: 40Recibido: 60Recibido: 80Flujo completado


Ejemplo 2: Flujos asíncronos con futures-rs

La biblioteca futures-rs proporciona el trait Stream, que es el equivalente asíncrono de Iterator. El siguiente ejemplo demuestra la creación de un flujo, su transformación y la recolección de resultados:



use futures::stream::{self, StreamExt};

#[tokio::main]async fn main() { let stream = stream::iter(1..=5) .map(|x| x * x) .filter(|x| futures::future::ready(x % 2 == 0));

let results: Vec<i32> = stream.collect().await; println!("Cuadrados de números pares: {:?}", results);}


Salida:

Cuadrados de números pares: [4, 16]


Ejemplo 3: Canales reactivos en async-std

Los canales (channels) son la base de los sistemas reactivos. La biblioteca async-std proporciona canales multiusuario que se pueden usar para transmitir eventos entre tareas:



use async_std::sync::channel;use async_std::task;

fn main() { let (sender, receiver) = channel::unbounded::<String>();

// Tarea emisora task::spawn(async move { sender.send("Hola".to_string()).await.unwrap(); sender.send("Mundo".to_string()).await.unwrap(); });

// Tarea receptora (escucha reactiva) task::block_on(async { while let Some(msg) = receiver.recv().await { println!("Mensaje recibido: {}", msg); } });}


Este patrón es la base de la arquitectura de aplicaciones orientadas a eventos en Rust.



Comparación de bibliotecas y recomendaciones

Recommendations