Immutable مقابل const في Rust: ما الفرق؟ دليل 2025

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

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

ابدأ الدورة

Immutable مقابل const في Rust: لماذا يختلط الأمر حتى على المطورين ذوي الخبرة؟

\n\n

هل سبق لك أن كتبت كودًا بلغة Rust وفجأة تساءلت: "توقف، لقد أعلنت متغيرًا باستخدام let، وهو غير قابل للتغيير. و const هو أيضًا ثابت. إذن ما الفرق؟". إذا كان الأمر كذلك، فأنت لست وحدك. سؤال "ما الفرق بين المتغيرات immutable و const في Rust؟" على Stack Overflow حصد آلاف المشاهدات. وهذا ليس من قبيل الصدفة.

\n\n

للوهلة الأولى، يبدو أن كلاً من let x = 5 و const X: i32 = 5 يفعلان الشيء نفسه: يمنعان تغيير القيمة. ولكن في Rust، وهي لغة أمان الذاكرة و الأداء في صميمها، يكمن الشيطان في التفاصيل. في عام 2025، فهم هذه التفاصيل ليس مجرد نظرية، بل ضرورة لكتابة كود فعال ومتوافق مع أسلوب اللغة.

\n\n

في هذه المقالة، سنوضح مرة واحدة وإلى الأبد: كيف يختلف المتغير immutable عن الثابت، ومتى نستخدم أيهما، وما هي أفضل الممارسات السارية الآن. هيا بنا!

\n\n

1. الفهم الأساسي: ماذا يقول المترجم؟

\n\n

لنبدأ بالأبسط. في Rust، المتغيرات تكون immutable (غير قابلة للتغيير) بشكل افتراضي. هذا يعني أنه بعد تعيين قيمة، لا يمكنك إعادة كتابتها.

\n\n
fn main() {\n    let x = 5;\n    // x = 6; // خطأ! لا يمكن تغيير متغير immutable\n    println!("x = {}", x);\n}
\n\n

وهذا مثال مع ثابت:

\n\n
const MAX_POINTS: u32 = 100_000;\n\nfn main() {\n    println!("MAX_POINTS = {}", MAX_POINTS);\n}
\n\n

بصريًا، يبدو الأمر متشابهًا. لكن مترجم Rust يعالجها بشكل مختلف تمامًا. وهنا يبدأ الجزء المثير للاهتمام.

\n\n

1.1. الفرق الرئيسي رقم 1: أين تعيش؟

\n\n
    \n
  • let — يعلن عن متغير. يوجد في المكدس (أو الكومة، إذا كان Box، String إلخ) وله عنوان في الذاكرة. يمكن أخذ مرجع إليه، تمريره إلى الدوال، نقله.
  • \n
  • const — يعلن عن ثابت. ليس له عنوان ثابت في الذاكرة. يقوم المترجم بتضمين قيمته مباشرة في الكود في مكان الاستخدام.
  • \n
\n\n

هذا هو الفرق الأساسي. const ليس متغيرًا، بل هو قيمة مسماة يتم استبدالها في مرحلة الترجمة.

\n\n
fn main() {\n    let x = 42;\n    let y = &x; // حسنًا، نأخذ مرجعًا للمتغير\n\n    const Z: i32 = 100;\n    // let w = &Z; // خطأ! الثابت ليس له عنوان، لا يمكن أخذ مرجع\n}
\n\n

2. الغوص العميق: الأداء والدلالات

\n\n

الآن بعد أن عرفنا "مكان الإقامة"، دعنا نحلل الجوانب المهمة الأخرى.

\n\n

2.1. عمر النطاق ونطاق الرؤية

\n

الثوابت تعيش في نطاق رؤية عام (أو داخل دالة، ولكن مع عمر static). إنها موجودة طوال فترة تشغيل البرنامج. يمكن الإعلان عنها خارج الدالة، وستكون متاحة في كل مكان.

\n\n

المتغيرات immutable تعيش فقط داخل الكتلة (دالة، حلقة، if). بمجرد انتهاء الكتلة، يتم تحرير الذاكرة.

\n\n
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\n

2.2. النوع والتعليقات التوضيحية

\n

بالنسبة لـ const، من الضروري تحديد نوع البيانات. بالنسبة لـ let، سيستنتجه المترجم بنفسه.

\n\n
const PI: f64 = 3.14159; // إلزامي: const الاسم: النوع = القيمة;\nlet pi = 3.14159; // المترجم سيفهم بنفسه أنها f64
\n\n

2.3. الحساب في مرحلة الترجمة (CTFE)

\n

يجب حساب قيمة const في مرحلة الترجمة.

المدونات

توصيات الكتب