المتغيرات في Rust: لماذا تكون البيانات غير قابلة للتعديل (Immutable) افتراضياً؟
ماذا سنتعلم اليوم؟ في هذا الدرس، سنتعمق في مفهوم المتغيرات في Rust، مع التركيز على سلوكها الافتراضي غير القابل للتعديل (Immutable) وكيفية التحكم في هذه الخاصية لإنشاء برامج آمنة وفعالة.
الخطوة 1: فهم المتغيرات غير القابلة للتعديل (Immutable)
في Rust، عندما تُعرّف متغيراً باستخدام الكلمة المفتاحية let، فإنه يكون غير قابل للتعديل افتراضياً. هذا يعني أنه بمجرد تعيين قيمة للمتغير، لا يمكنك تغيير هذه القيمة لاحقاً. هذا السلوك يعزز السلامة ويقلل من الأخطاء، خاصة في البرمجة المتزامنة.
ملاحظة تقنية: التغيير الافتراضي للمتغيرات إلى 'غير قابل للتعديل' هو قرار تصميمي أساسي في Rust يهدف إلى المساعدة في كتابة شيفرات خالية من الأخطاء، خصوصاً تلك المتعلقة بالوصول المتزامن للبيانات (Data Races).
لنرى ماذا يحدث عندما نحاول تغيير قيمة متغير غير قابل للتعديل:
fn main() {
let x = 5; // تعريف متغير 'x' بقيمة 5. هو غير قابل للتعديل افتراضياً.
println!("قيمة x الأولية: {}", x);
// x = 6; // إذا قمت بإزالة التعليق عن هذا السطر، سيحدث خطأ في الترجمة!
// println!("قيمة x بعد محاولة التعديل: {}", x);
}
الخطوة 2: جعل المتغيرات قابلة للتعديل (Mutable) باستخدام mut
إذا كنت بحاجة إلى تغيير قيمة متغير بعد تعريفه، يجب عليك استخدام الكلمة المفتاحية mut (اختصار لـ 'mutable') عند تعريفه. هذا يخبر Rust صراحة أنك تنوي تعديل هذا المتغير لاحقاً.
ملاحظة تقنية: استخدام mut هو اختيار واعٍ وواضح للمبرمج، مما يجعل نواياك واضحة لكل من يقرأ الكود ويساعد Rust على فرض قواعد السلامة حتى مع المتغيرات القابلة للتعديل.
إليك كيفية تعريف متغير قابل للتعديل:
fn main() {
let mut y = 10; // تعريف متغير 'y' بقيمة 10 وجعله قابلاً للتعديل باستخدام 'mut'.
println!("قيمة y الأولية: {}", y);
y = 15; // الآن يمكننا تعديل قيمة 'y' بنجاح.
println!("قيمة y بعد التعديل: {}", y);
}
الخطوة 3: التظليل (Shadowing)
تقدم Rust مفهوماً مثيراً للاهتمام يُسمى التظليل (Shadowing). يسمح لك التظليل بتعريف متغير جديد بنفس اسم متغير سابق، لكن المتغير الجديد 'يظلل' المتغير القديم. هذا يعني أن المتغير الجديد سيصبح مرئياً في النطاق الحالي، بينما يظل المتغير القديم موجوداً في الذاكرة ولكنه غير قابل للوصول إليه بهذا الاسم. يمكن أن يكون للمتغير الجديد نوع مختلف تماماً عن المتغير القديم.
ملاحظة تقنية: التظليل يختلف عن جعل المتغير قابلاً للتعديل (mutability). في التظليل، أنت تنشئ متغيراً جديداً تماماً، بينما في 'mutability' أنت تعدّل نفس المتغير في مكانه. التظليل مفيد عندما تريد تحويل قيمة متغير أو تغيير نوعه دون الحاجة إلى اختراع اسم متغير جديد.
إليك مثال يوضح التظليل:
fn main() {
let z = "مرحباً"; // تعريف المتغير 'z' كـ &str (سلسلة نصية).
println!("قيمة z الأولية: {}", z);
let z = z.len(); // تظليل المتغير 'z' بمتغير جديد يحمل طول السلسلة (نوع usize).
println!("قيمة z بعد التظليل (الطول): {}", z);
let z = z + 1; // يمكننا تظليل المتغير 'z' مرة أخرى، هذه المرة بزيادة قيمته الرقمية.
println!("قيمة z بعد التظليل مرة أخرى: {}", z);
}
الكود النهائي الكامل
هذا هو الكود الذي يجمع كل المفاهيم التي ناقشناها في درس اليوم:
fn main() {
// الخطوة 1: المتغيرات غير القابلة للتعديل افتراضياً
let x = 5;
println!("قيمة x الأولية: {}", x);
// x = 6; // سيؤدي هذا إلى خطأ في الترجمة: <code dir="ltr" style="background:#f3f4f6; color:#0056b3; padding:2px 6px; border-radius:4px; font-family:monospace; direction:ltr !important; display:inline-block;">cannot assign twice to immutable variable </code>x`<code dir="ltr" style="background:#f3f4f6; color:#0056b3; padding:2px 6px; border-radius:4px; font-family:monospace; direction:ltr !important; display:inline-block;">
// println!("قيمة x بعد محاولة التعديل: {}", x);
println!("---------------------");
// الخطوة 2: المتغيرات القابلة للتعديل باستخدام </code>mut`
let mut y = 10;
println!("قيمة y الأولية: {}", y);
y = 15;
println!("قيمة y بعد التعديل: {}", y);
println!("---------------------");
// الخطوة 3: التظليل (Shadowing)
let z = "مرحباً";
println!("قيمة z الأولية: {}", z);
let z = z.len(); // تظليل 'z' بقيمة جديدة ونوع مختلف
println!("قيمة z بعد التظليل (الطول): {}", z);
let z = z + 1; // تظليل 'z' مرة أخرى
println!("قيمة z بعد التظليل مرة أخرى: {}", z);
}
النتيجة المتوقعة
عند تشغيل الكود النهائي، ستحصل على المخرجات التالية في الطرفية:
قيمة x الأولية: 5 --------------------- قيمة y الأولية: 10 قيمة y بعد التعديل: 15 --------------------- قيمة z الأولية: مرحباً قيمة z بعد التظليل (الطول): 5 قيمة z بعد التظليل مرة أخرى: 6
بهذا نكون قد فهمنا لماذا تكون المتغيرات في Rust غير قابلة للتعديل افتراضياً، وكيفية استخدام mut لجعلها قابلة للتعديل، ومفهوم التظليل (Shadowing) كطريقة قوية ومرنة لإعادة تعريف المتغيرات.