علامات الاقتباس الغامضة في Rust: ما الذي تخفيه المعرفات بين علامتي اقتباس؟

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

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

ابدأ الدورة

ما الذي تخفيه علامة الاقتباس المفردة؟ تعرف على lifetime في Rust



إذا سبق لك أن فتحت كودًا بلغة Rust ورأيت تركيبات غريبة مثل &'a str أو fn foo<'a>()، فبالتأكيد تساءلت: «ما هذه العلامات الاقتباسية؟». أنت لست وحدك - هذا السؤال حصد آلاف المشاهدات على Stack Overflow وأصبح كابوسًا حقيقيًا للمبتدئين.



اليوم سنفهم هذه الرموز الغامضة مرة وإلى الأبد. مفاجأة: خلف علامات الاقتباس تختبئ واحدة من أقوى مفاهيم Rust - زمن الحياة (lifetime). ونعم، الأمر ليس مخيفًا كما يبدو!



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



المعرفات بعلامة الاقتباس: ليست مجرد زينة



في Rust، المعرفات التي تبدأ بعلامة اقتباس مفردة (مثل 'a، 'static، 'b) هي تعليقات توضيحية لزمن الحياة. لا تؤثر على المدة التي تعيشها المتغيرات، بل تخبر المترجم بالعلاقات بين أزمنة حياة المراجع المختلفة.



تخيل أنك محقق، ومترجم Rust هو مساعدك. تقول: «يجب أن يعيش هذان المرجعان بنفس المدة»، وتضع عليهما علامة 'a. يتحقق المترجم من عدم مخالفتك لهذه القاعدة. إذا خالفتها - تحصل على خطأ في مرحلة التجميع، وليس في وقت التشغيل.



لماذا تبدو بهذا الشكل؟



لم يتم اختيار بناء الجملة بعلامة الاقتباس عشوائيًا. في Rust، تُستخدم علامة الاقتباس للإشارة إلى التسميات (labels) - وهي نوع من «الأسماء» للفترات الزمنية. هذا الأسلوب موجود أيضًا في لغات أخرى، لكنه في Rust أصبح عنصرًا أساسيًا في نظام أمان الذاكرة.



إليك بعض الأمثلة حيث ستواجه هذه التسميات:



  • fn longest<'a>(x: &'a str, y: &'a str) -> &'a str - دالة تُرجع مرجعًا لا يعيش أطول من كلا الوسيطين.
  • struct Book<'a> { title: &'a str } - هيكل يحتوي على مرجع بزمن حياة.
  • &'static str - مرجع إلى سلسلة ثابتة تعيش طوال فترة البرنامج.


كيف تقرأ وتفهم lifetime؟



دعنا نحلل بعض الأمثلة الحقيقية من الكود. ستساعدك على التوقف عن الخوف من علامات الاقتباس والبدء في استخدامها.



مثال 1: دالة بزمن حياة واحد



لنفترض أننا نكتب دالة تُرجع أطول سلسلتين:



fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {    if x.len() > y.len() { x } else { y }}

fn main() { let string1 = String::from("hello"); let result; { let string2 = String::from("world"); result = longest(&string1, &string2); } // println!("{}", result); // خطأ في التجميع!}


ماذا يحدث هنا؟ نقول للمترجم: «النتيجة ستعيش لمدة لا تزيد عن x و y معًا». عندما يخرج string2 عن النطاق، يصبح result غير صالح. يرى المترجم ذلك ولا يسمح لنا بإطلاق النار على أقدامنا.



مثال 2: هيكل بمرجع



غالبًا ما يحاول المبتدئون تخزين المراجع في الهياكل ويحصلون على أخطاء. الحل هو تحديد زمن الحياة بشكل صريح:



#[derive(Debug)]struct Book<'a> {    title: &'a str,    author: &'a str,}

fn main() { let title = String::from("The Rust Programming Language"); let author = String::from("Steve Klabnik"); let book = Book { title: &title, author: &author, }; println!("{:?}", book);}


هنا يعني 'a أن title و author يجب أن يعيشا على الأقل بنفس مدة الهيكل Book. إذا حاولت حذف

المدونات

توصيات الكتب