Immutable مقابل const في Rust: لماذا يختلط الأمر حتى على المطورين ذوي الخبرة؟
\n\nهل سبق لك أن كتبت كودًا بلغة Rust وفجأة تساءلت: "توقف، لقد أعلنت متغيرًا باستخدام let، وهو غير قابل للتغيير. و const هو أيضًا ثابت. إذن ما الفرق؟". إذا كان الأمر كذلك، فأنت لست وحدك. سؤال "ما الفرق بين المتغيرات immutable و const في Rust؟" على Stack Overflow حصد آلاف المشاهدات. وهذا ليس من قبيل الصدفة.
للوهلة الأولى، يبدو أن كلاً من let x = 5 و const X: i32 = 5 يفعلان الشيء نفسه: يمنعان تغيير القيمة. ولكن في Rust، وهي لغة أمان الذاكرة و الأداء في صميمها، يكمن الشيطان في التفاصيل. في عام 2025، فهم هذه التفاصيل ليس مجرد نظرية، بل ضرورة لكتابة كود فعال ومتوافق مع أسلوب اللغة.
في هذه المقالة، سنوضح مرة واحدة وإلى الأبد: كيف يختلف المتغير immutable عن الثابت، ومتى نستخدم أيهما، وما هي أفضل الممارسات السارية الآن. هيا بنا!
\n\n1. الفهم الأساسي: ماذا يقول المترجم؟
\n\nلنبدأ بالأبسط. في Rust، المتغيرات تكون immutable (غير قابلة للتغيير) بشكل افتراضي. هذا يعني أنه بعد تعيين قيمة، لا يمكنك إعادة كتابتها.
\n\nfn main() {\n let x = 5;\n // x = 6; // خطأ! لا يمكن تغيير متغير immutable\n println!("x = {}", x);\n}\n\nوهذا مثال مع ثابت:
\n\nconst MAX_POINTS: u32 = 100_000;\n\nfn main() {\n println!("MAX_POINTS = {}", MAX_POINTS);\n}\n\nبصريًا، يبدو الأمر متشابهًا. لكن مترجم Rust يعالجها بشكل مختلف تمامًا. وهنا يبدأ الجزء المثير للاهتمام.
\n\n1.1. الفرق الرئيسي رقم 1: أين تعيش؟
\n\n- \n
let— يعلن عن متغير. يوجد في المكدس (أو الكومة، إذا كانBox،Stringإلخ) وله عنوان في الذاكرة. يمكن أخذ مرجع إليه، تمريره إلى الدوال، نقله. \n const— يعلن عن ثابت. ليس له عنوان ثابت في الذاكرة. يقوم المترجم بتضمين قيمته مباشرة في الكود في مكان الاستخدام. \n
هذا هو الفرق الأساسي. const ليس متغيرًا، بل هو قيمة مسماة يتم استبدالها في مرحلة الترجمة.
fn main() {\n let x = 42;\n let y = &x; // حسنًا، نأخذ مرجعًا للمتغير\n\n const Z: i32 = 100;\n // let w = &Z; // خطأ! الثابت ليس له عنوان، لا يمكن أخذ مرجع\n}\n\n2. الغوص العميق: الأداء والدلالات
\n\nالآن بعد أن عرفنا "مكان الإقامة"، دعنا نحلل الجوانب المهمة الأخرى.
\n\n2.1. عمر النطاق ونطاق الرؤية
\nالثوابت تعيش في نطاق رؤية عام (أو داخل دالة، ولكن مع عمر static). إنها موجودة طوال فترة تشغيل البرنامج. يمكن الإعلان عنها خارج الدالة، وستكون متاحة في كل مكان.
المتغيرات immutable تعيش فقط داخل الكتلة (دالة، حلقة، if). بمجرد انتهاء الكتلة، يتم تحرير الذاكرة.
const GLOBAL_CONST: i32 = 10;\n\nfn main() {\n let local_var = 20;\n // local_var يعيش فقط داخل main\n}\n// local_var لم يعد موجودًا\n// GLOBAL_CONST لا يزال متاحًا\n\n2.2. النوع والتعليقات التوضيحية
\nبالنسبة لـ const، من الضروري تحديد نوع البيانات. بالنسبة لـ let، سيستنتجه المترجم بنفسه.
const PI: f64 = 3.14159; // إلزامي: const الاسم: النوع = القيمة;\nlet pi = 3.14159; // المترجم سيفهم بنفسه أنها f64\n\n2.3. الحساب في مرحلة الترجمة (CTFE)
\nيجب حساب قيمة const في مرحلة الترجمة.