البرمجة التفاعلية في Rust: نظرة عامة على الأدوات وأمثلة كود
البرمجة التفاعلية هي نموذج يركز على التدفقات غير المتزامنة للبيانات ونشر التغييرات. في نظام Rust البيئي، يتم تنفيذها من خلال مكتبات قوية مثل RxRust (Reactive Extensions)، futures-rs و async-std. تتيح هذه الأدوات بناء أنظمة أنيقة، متسامحة مع الأخطاء وعالية الأداء، بدءًا من تطبيقات الواجهات الرسومية وصولاً إلى الخدمات الشبكية. في هذه المقالة، سنشرح المفاهيم الأساسية، ونعرض أمثلة عملية، ونساعدك في اختيار المكتبة المناسبة لمشروعك في Rust.
المكتبات الرئيسية للبرمجة التفاعلية في Rust
أشهر المكتبات للبرمجة التفاعلية في Rust تشمل:
- RxRust — نسخة من ReactiveX (Rx). توفر Observable، Observer، عوامل تشغيل مثل map، filter، merge وغيرها. مثالية لمعالجة الأحداث وتدفقات البيانات.
- futures-rs — المكتبة الأساسية للحسابات غير المتزامنة. تتضمن Stream، Future، Sink. تشكل أساس العديد من الأنظمة التفاعلية.
- async-std — مكتبة قياسية غير متزامنة. توفر إصدارات غير متزامنة من الإدخال/الإخراج للملفات، العمليات الشبكية، والقنوات (channels) للتدفقات التفاعلية.
- tokio — بيئة تشغيل غير متزامنة تدعم تعدد الخيوط. تُستخدم غالبًا مع futures-rs لبناء تطبيقات شبكية تفاعلية.
مثال 1: استخدام RxRust لمعالجة الأحداث
يتيح RxRust إنشاء Observable من المكررات، الأحداث أو المصادر غير المتزامنة. فيما يلي مثال بسيط لتوليد الأرقام، التصفية والاشتراك في التدفق:
use rxrust::prelude::*;
fn main() { // إنشاء Observable من نطاق أرقام observable::from_iter(1..10) .filter(|x| x % 2 == 0) // الاحتفاظ فقط بالأرقام الزوجية .map(|x| x * 10) // الضرب في 10 .subscribe( |x| println!("تم الاستلام: {}", x), |err| eprintln!("خطأ: {}", err), || println!("اكتمل التدفق"), );}نتيجة التنفيذ:
تم الاستلام: 20تم الاستلام: 40تم الاستلام: 60تم الاستلام: 80اكتمل التدفقمثال 2: التدفقات غير المتزامنة مع futures-rs
توفر مكتبة futures-rs النمط Stream، وهو النظير غير المتزامن لـ Iterator. يوضح المثال التالي إنشاء تدفق، تحويله وجمع النتائج:
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!("مربعات الأعداد الزوجية: {:?}", results);}الإخراج:
مربعات الأعداد الزوجية: [4, 16]مثال 3: القنوات التفاعلية في async-std
القنوات (channels) هي أساس الأنظمة التفاعلية. توفر مكتبة async-std قنوات متعددة المستخدمين يمكن استخدامها لنقل الأحداث بين المهام:
use async_std::sync::channel;use async_std::task;
fn main() { let (sender, receiver) = channel::unbounded::<String>();
// مهمة المرسل task::spawn(async move { sender.send("مرحباً".to_string()).await.unwrap(); sender.send("العالم".to_string()).await.unwrap(); });
// مهمة المستقبل (المستمع التفاعلي) task::block_on(async { while let Some(msg) = receiver.recv().await { println!("تم استلام الرسالة: {}", msg); } });}هذا النمط يشكل أساس بنية التطبيقات الموجهة بالأحداث في Rust.