Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

سمة Drop

جزء من قسم Object Oriented Programming في رحلة Rust على Coddy — الدرس 56 من 61.

عندما تخرج قيمة عن النطاق (scope) في لغة Rust، يتم تنظيفها تلقائيًا. ولكن ماذا لو كنت بحاجة إلى تشغيل كود مخصص في تلك اللحظة—مثل تسجيل البيانات، أو تحرير مورد، أو إرسال رسالة أخيرة؟ تتيح لك سمة Drop تحديد ما يحدث بالضبط عندما يكون الـ struct الخاص بك على وشك التدمير.

تمتلك سمة Drop طريقة واحدة تسمى drop تأخذ &mut self:

struct Connection {
    id: u32,
}

impl Drop for Connection {
    fn drop(&mut self) {
        println!("Connection {} closed.", self.id);
    }
}

لا تقوم أبداً باستدعاء drop مباشرةً—تقوم Rust باستدعائه تلقائياً عندما تخرج القيمة عن النطاق (scope):

fn main() {
    let conn = Connection { id: 42 };
    println!("Using connection...");
}  // "Connection 42 closed." تُطبع هنا تلقائياً

سيكون الناتج:

Using connection...
Connection 42 closed.

هذا هو إصدار لغة Rust للمدمر (destructor). يُستخدم بشكل شائع لمهام التنظيف: إغلاق مقابض الملفات، أو قطع الاتصال بالخوادم، أو تحرير الموارد التي لا تستطيع Rust إدارتها تلقائيًا. تضمن سمة Drop تشغيل كود التنظيف الخاص بك، حتى لو انتهى النطاق بسبب عودة مبكرة.

challenge icon

التحدي

سهل

لنقم ببناء نظام لإدارة الموارد يوضح التنظيف التلقائي! ستقوم بإنشاء هيكل FileHandle يحاكي فتح وإغلاق الملفات—عندما يخرج المقبض (handle) عن النطاق (scope)، سيعلن تلقائيًا أنه تم إغلاق الملف.

ستقوم بتنظيم الكود الخاص بك عبر ملفين:

  • file_handle.rs: قم بتعريف هيكل FileHandle عام مع حقل filename عام (String). قم بتنفيذ دالة مرتبطة new تقوم بإنشاء FileHandle وتطبع رسالة عند "فتح" الملف. ثم قم بتنفيذ سمة Drop بحيث عندما يتم إسقاط المقبض، فإنه يطبع رسالة إغلاق.
  • main.rs: قم باستيراد وحدة file_handle الخاصة بك وأنشئ دالة تسمى process_file تأخذ اسم ملف، وتنشئ FileHandle داخل نطاق محلي، وتطبع رسالة معالجة بينما الملف "مفتوح". سيتم تشغيل تنفيذ Drop تلقائيًا عند انتهاء النطاق. استدعِ هذه الدالة مع المدخلات المقدمة.

عند إنشاء FileHandle، يجب أن يطبع:

Opening file: {filename}

أثناء المعالجة (داخل النطاق)، اطبع:

Processing {filename}...

عندما يتم إسقاط FileHandle (ينتهي النطاق)، يجب أن يطبع:

Closing file: {filename}

على سبيل المثال، مع المدخلات data.txt:

Opening file: data.txt
Processing data.txt...
Closing file: data.txt

ومع المدخلات config.json:

Opening file: config.json
Processing config.json...
Closing file: config.json

ستتلقى مدخلاً واحدًا: سلسلة اسم الملف (filename string).

ورقة مرجعية

تسمح لك سمة Drop بتعريف كود تنظيف مخصص يتم تشغيله تلقائيًا عندما تخرج قيمة ما عن النطاق (scope).

تحتوي سمة Drop على طريقة واحدة تسمى drop تأخذ &mut self:

struct Connection {
    id: u32,
}

impl Drop for Connection {
    fn drop(&mut self) {
        println!("Connection {} closed.", self.id);
    }
}

لا تقوم أبدًا باستدعاء drop مباشرةً—تقوم لغة Rust باستدعائها تلقائيًا عندما تخرج القيمة عن النطاق:

fn main() {
    let conn = Connection { id: 42 };
    println!("Using connection...");
}  // "Connection 42 closed." تُطبع هنا تلقائيًا

تُستخدم سمة Drop بشكل شائع لمهام التنظيف مثل إغلاق مقابض الملفات، أو قطع الاتصال بالخوادم، أو تحرير الموارد. وهي تضمن تشغيل كود التنظيف الخاص بك، حتى لو انتهى النطاق بسبب إرجاع مبكر.

جرّب بنفسك

mod file_handle;

use file_handle::FileHandle;

// TODO: قم بتنفيذ الدالة process_file
// يجب أن تقوم بـ:
// 1. إنشاء نطاق محلي (باستخدام الأقواس المتعرجة {})
// 2. داخل ذلك النطاق، قم بإنشاء FileHandle باستخدام FileHandle::new()
// 3. طباعة رسالة المعالجة: "Processing {filename}..."
// 4. عند انتهاء النطاق، سيتم استدعاء Drop تلقائياً
fn process_file(filename: &str) {
    // TODO: قم بتنفيذ هذه الدالة
}

fn main() {
    let mut input = String::new();
    std::io::stdin().read_line(&mut input).expect("Failed to read line");
    let filename = input.trim();
    
    process_file(filename);
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس Object Oriented Programming