البرمجة الوظيفية في Rust: الأساليب والأمثلة

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

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

ابدأ الدورة

مقدمة في البرمجة الوظيفية بلغة Rust

Rust هي لغة متعددة النماذج، تدعم إلى جانب الأساليب الأمرية والموجهة للكائنات البرمجة الوظيفية بنشاط. تتيح الأدوات المدمجة مثل الإغلاقات (closures) والمكررات (iterators) ونظام الأنواع القوي والثبات الافتراضي كتابة كود موجز وآمن ومعبّر. في هذه المقالة، سنشرح المفاهيم الأساسية للنهج الوظيفي في Rust ونوضح كيفية تطبيقها عمليًا.



أساسيات النهج الوظيفي: الثبات والدوال النقية

تقوم البرمجة الوظيفية على ركيزتين: ثبات البيانات والدوال النقية. تشجع Rust على الثبات — افتراضيًا، جميع المتغيرات غير قابلة للتغيير. لتغيير قيمة، يجب تحديد mut صراحةً.

fn main() {    let x = 5; // متغير غير قابل للتغيير    // x = 6; // خطأ في الترجمة    let mut y = 10;    y += 5; // مسموح به لأن y قابل للتغيير    println!("x = {}, y = {}", x, y);}

الدالة النقية ليس لها آثار جانبية وتعيد دائمًا نفس النتيجة لنفس الوسائط. تسمح Rust بكتابة مثل هذه الدوال، لكنها لا تُجبر على ذلك — يمكنك مزج الأنماط بحرية.

fn add(a: i32, b: i32) -> i32 {    a + b // دالة نقية}


الإغلاقات (closures) — دوال مجهولة

الإغلاقات في Rust هي دوال مجهولة يمكنها التقاط المتغيرات من النطاق المحيط. تُعرّف باستخدام الصيغة |parameters| body. هناك ثلاثة أنواع من الإغلاقات حسب طريقة الالتقاط: بالمرجع (&T)، بالمرجع القابل للتغيير (&mut T)، وبالقيمة (T).

مثال بسيط على إغلاق

fn main() {    let factor = 2;    let multiply = |x: i32| x * factor;    println!("{}", multiply(10)); // 20}

إغلاق مع التقاط قابل للتغيير

fn main() {    let mut counter = 0;    let mut increment = || {        counter += 1;        counter    };    println!("{}", increment()); // 1    println!("{}", increment()); // 2}

تُستخدم الإغلاقات على نطاق واسع مع المكررات ولتمرير السلوك إلى دوال الرتبة الأعلى.



المكررات والسلاسل الوظيفية

المكررات في Rust هي واحدة من أقوى التجريدات الوظيفية. بدلاً من الحلقات، يمكنك بناء سلاسل من دوال مثل map وfilter وfold وغيرها. المكررات كسولة — يتم إجراء الحسابات فقط عند استدعاء المستهلك (مثل collect أو for_each).

مثال: التصفية والتحويل

fn main() {    let numbers = vec![1, 2, 3, 4, 5, 6];    let result: Vec<i32> = numbers        .iter()        .filter(|&x| x % 2 == 0) // نترك الأعداد الزوجية        .map(|x| x * x)          // نربّع        .collect();    println!("{:?}", result); // [4, 16, 36]}

الطي (fold) — تجميع القيم

fn main() {    let numbers = vec![1, 2, 3, 4];    let sum = numbers.iter().fold(0, |acc, x| acc + x);    println!("المجموع: {}", sum); // 10}

تجعل المكررات الكود تصريحيًا: تصف ماذا يجب فعله، وليس كيف. هذا يقلل من احتمالية الأخطاء ويحسن قابلية القراءة.



مطابقة الأنماط (pattern matching)

بنية match هي عنصر أساسي في الأسلوب الوظيفي في Rust. تسمح بتحليل هياكل البيانات المعقدة، ومعالجة خيارات Option وResult، وكتابة فحوصات شاملة.

مثال أساسي

fn describe_number(n: i32) -> &'static str {    match n {        0 => "صفر",        1 | 2 => "رقم صغير",        3..=10 => "رقم متوسط",        _ if n < 0 => "سلبي",        _ => "رقم كبير"    }}

المدونات

توصيات الكتب