لماذا Rust هو المرشح المثالي للأتمتة
عندما يتعلق الأمر بأتمتة المهام الروتينية، يتذكر معظم المطورين على الفور Python أو Bash. وهذا منطقي: فهي بسيطة ومرنة ولديها عدد هائل من المكتبات الجاهزة. ولكن ماذا تفعل إذا بدأ السكريبت في التباطؤ على كميات كبيرة من البيانات؟ أو إذا كنت بحاجة إلى ضمان عدم تعطل البرنامج مع خطأ غامض في أكثر اللحظات غير المناسبة؟
هنا تظهر Rust على المسرح. لغة تجمع بين أداء C/C++ مع أمان الذاكرة على مستوى اللغات المُدارة. لمهام الأتمتة، يوفر هذا ثلاث مزايا رئيسية:
- السرعة — يتم تجميع Rust إلى كود أصلي، مما يعطي مكسبًا يتراوح بين 10-100 مرة مقارنة باللغات المفسرة.
- الموثوقية — يكتشف المترجم معظم الأخطاء قبل التشغيل (سباقات البيانات، المؤشرات المعلقة، معالجات الأخطاء المنسية).
- توفير الموارد — الحد الأدنى من استهلاك الذاكرة والمعالج يسمح بتشغيل الأدوات المساعدة على Raspberry Pi أو الخوادم القديمة.
في هذه المقالة، سنحلل ثلاثة سيناريوهات حقيقية للأتمتة باستخدام Rust: إعادة تسمية الملفات دفعة واحدة، مراقبة موارد الويب، وتحليل السجلات. سترى كيفية كتابة كود موجز ولكن موثوق، وستفهم متى تبرر Rust حقًا تكاليف تعلمها.
السيناريو 1: إعادة تسمية الملفات دفعة واحدة مع التحقق والسجلات
تخيل: لديك مجلد يحتوي على مئات الصور بالصيغة IMG_20231201_143022.jpg. تحتاج إلى إعادة تسميتها إلى الصيغة 2023-12-01_photo_001.jpg. في Bash يمكن القيام بذلك في سطرين، ولكن ماذا لو كانت الأسماء تحتوي على أحرف غير قياسية، أو مكررات، أو تحتاج إلى سجل مفصل؟
Rust مع نظام الأنواع الصارم والـ crate std::fs ستتعامل مع هذا بأناقة وأمان.
التنفيذ باستخدام Rust
use std::fs;use std::path::Path;use std::io;use chrono::NaiveDateTime;
fn main() -> io::Result<()> { let dir = Path::new("./photos"); let mut counter = 1u32;
for entry in fs::read_dir(dir)? { let entry = entry?; let path = entry.path(); if path.extension().map_or(false, |ext| ext == "jpg") { let stem = path.file_stem().unwrap().to_str().unwrap(); // تحليل التاريخ من الاسم: IMG_20231201_143022 -> 2023-12-01 14:30:22 if let Some(date_part) = stem.split('_').nth(1) { if let Ok(dt) = NaiveDateTime::parse_from_str( &format!("{} {}", &date_part[0..8], &date_part[8..14] ), "%Y%m%d %H%M%S" ) { let new_name = format!( "{}_photo_{:03}.jpg", dt.format("%Y-%m-%d"), counter ); let new_path = dir.join(&new_name); fs::rename(&path, &new_path)?; println!("✅ {} -> {}", path.display(), new_name); counter += 1; } else { eprintln!("⚠️ لم يتم تحليل التاريخ: {}", path.display()); } } } } println!("🎉 تمت معالجة {} ملف", counter - 1); Ok(())}لاحظ معالجة الأخطاء: io::Result و eprintln للملفات التي بها مشاكل. سيجبرك مترجم Rust على معالجة كل عطل محتمل بشكل صريح - سواء كان نقص أذونات القراءة أو تنسيق تاريخ غير صحيح. هذا يعني أن سكريبت الأتمتة الخاص بك لن "يصمت" عند أول خطأ، بل سيبلغ بوضوح عما حدث من خطأ.
مقياس الأداء: بالنسبة لـ 10,000 ملف، يتم تنفيذ نسخة Rust في 0.8 ثانية، بينما السكريبت المماثل في Pyth