البرمجة الوظيفية في Rust: المستوى المتقدم
\n\nRust هي لغة متعددة النماذج تجمع بسلاسة بين الأساليب الأمرية والموجهة للكائنات والوظيفية. على المستوى المتقدم، تتيح البرمجة الوظيفية في Rust كتابة كود أكثر أمانًا وتعبيرًا وإيجازًا. في هذه المقالة، سنشرح المفاهيم الأساسية: الإغلاقات مع التقاط البيئة، المكررات المتقدمة، الدوال الوظيفية والمونادات باستخدام Option و Result، بالإضافة إلى الكاري وتركيب الدوال.
1. الإغلاقات: الملكية، الاقتراض، والقابلية للتغيير
\n\nالإغلاقات في Rust ليست مجرد دوال مجهولة. يمكنها التقاط المتغيرات من النطاق المحيط بثلاث طرق: بالمرجع (&T)، بالمرجع القابل للتغيير (&mut T)، وبالقيمة (T). يختار المترجم تلقائيًا السمة الأقل تقييدًا: Fn أو FnMut أو FnOnce.
لننظر إلى مثال مع الالتقاط بالقيمة واستخدام move:
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\nfn 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.
2. المكررات المتقدمة: السلاسل، المحولات، والحسابات الكسولة
\n\nالمكررات في Rust هي أداة قوية للأسلوب الوظيفي. إنها كسولة: تحدث الحسابات فقط عند استدعاء الطريقة النهائية (collect، for_each، fold، إلخ).
لننظر إلى خط أنابيب معقد لمعالجة البيانات:
\n\nfn 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 للتراكم:
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. هذا يوفر الذاكرة ويحسن الأداء.
3. المونادات Option و Result: معالجة الأخطاء الوظيفية
\n\nفي البرمجة الوظيفية، Option و Result هما مونادات. تسمحان بمعالجة متسلسلة للقيم الاختيارية والأخطاء دون استخدام match أو if let المتداخلة.
لننظر إلى سيناريو نموذجي مع فحوصات متداخلة:
\n\nالمدونات
توصيات الكتب
اقرأ أيضًا