البرمجة الوظيفية في Rust: تقنيات وأساليب متقدمة

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

البرمجة الوظيفية في Rust: المستوى المتقدم

\n\n

Rust هي لغة متعددة النماذج تجمع بسلاسة بين الأساليب الأمرية والموجهة للكائنات والوظيفية. على المستوى المتقدم، تتيح البرمجة الوظيفية في Rust كتابة كود أكثر أمانًا وتعبيرًا وإيجازًا. في هذه المقالة، سنشرح المفاهيم الأساسية: الإغلاقات مع التقاط البيئة، المكررات المتقدمة، الدوال الوظيفية والمونادات باستخدام Option و Result، بالإضافة إلى الكاري وتركيب الدوال.

\n\n

1. الإغلاقات: الملكية، الاقتراض، والقابلية للتغيير

\n\n

الإغلاقات في Rust ليست مجرد دوال مجهولة. يمكنها التقاط المتغيرات من النطاق المحيط بثلاث طرق: بالمرجع (&T)، بالمرجع القابل للتغيير (&mut T)، وبالقيمة (T). يختار المترجم تلقائيًا السمة الأقل تقييدًا: Fn أو FnMut أو FnOnce.

\n\n

لننظر إلى مثال مع الالتقاط بالقيمة واستخدام move:

\n\n
fn main() {\n    let data = vec![1, 2, 3];\n    \n    // الالتقاط بالقيمة (move) - تنتقل الملكية إلى الإغلاق\n    let closure = move || {\n        println!("{:?}", data);\n        // data لم تعد متاحة في الدالة الرئيسية\n    };\n    \n    closure();\n    // println!("{:?}", data); // خطأ: تم نقل data\n}\n
\n\n

تقنية متقدمة - استخدام الإغلاقات لإنشاء مصانع للدوال:

\n\n
fn make_multiplier(factor: i32) -> impl Fn(i32) -> i32 {\n    move |x| x * factor\n}\n\nfn main() {\n    let double = make_multiplier(2);\n    let triple = make_multiplier(3);\n    \n    println!("{}", double(5));  // 10\n    println!("{}", triple(5));  // 15\n}\n
\n\n

هنا impl Fn(i32) -> i32 هو نوع الإغلاق المُعاد. يقوم Rust تلقائيًا بإنشاء نوع مجهول يقوم بتنفيذ السمة Fn.

\n\n

2. المكررات المتقدمة: السلاسل، المحولات، والحسابات الكسولة

\n\n

المكررات في Rust هي أداة قوية للأسلوب الوظيفي. إنها كسولة: تحدث الحسابات فقط عند استدعاء الطريقة النهائية (collect، for_each، fold، إلخ).

\n\n

لننظر إلى خط أنابيب معقد لمعالجة البيانات:

\n\n
fn process_data(data: Vec<i32>) -> Vec<i32> {\n    data.iter()\n        .filter(|&x| x > 0)                     // نترك الأرقام الموجبة\n        .map(|x| x * 2)                          // نضاعف\n        .enumerate()                             // نضيف الفهارس\n        .filter(|(i, _)| i % 2 == 0)             // الفهارس الزوجية\n        .map(|(_, x)| x)                         // نستخرج القيمة\n        .collect()                               // الطريقة النهائية\n}\n
\n\n

تقنية متقدمة - استخدام flat_map للعمل مع الهياكل المتداخلة و fold للتراكم:

\n\n
fn main() {\n    let nested = vec![vec![1, 2], vec![3, 4, 5], vec![6]];\n    \n    let flattened: Vec<i32> = nested.iter()\n        .flat_map(|v| v.iter())\n        .copied()\n        .collect();\n    \n    println!("{:?}", flattened); // [1, 2, 3, 4, 5, 6]\n    \n    // fold - النظير الوظيفي لـ reduce\n    let sum = flattened.iter()\n        .fold(0, |acc, x| acc + x);\n    \n    println!("المجموع: {}", sum); // 21\n}\n
\n\n

من المهم التذكر: سلاسل المكررات لا تنشئ مجموعات وسيطة ما لم يتم استدعاء collect. هذا يوفر الذاكرة ويحسن الأداء.

\n\n

3. المونادات Option و Result: معالجة الأخطاء الوظيفية

\n\n

في البرمجة الوظيفية، Option و Result هما مونادات. تسمحان بمعالجة متسلسلة للقيم الاختيارية والأخطاء دون استخدام match أو if let المتداخلة.

\n\n

لننظر إلى سيناريو نموذجي مع فحوصات متداخلة:

\n\n


                
                

المدونات

توصيات الكتب