سمة Drop
جزء من قسم البرمجة كائنية التوجه في رحلة Rust على Coddy. الدرس 56 من 61.
عندما تخرج قيمة عن نطاقها في Rust، يتم تنظيفها automatically. لكن ماذا لو احتجت إلى تشغيل تعليمات برمجية مخصصة في تلك اللحظة، مثل تسجيل الأحداث، أو تحرير مورد، أو إرسال رسالة نهائية؟ تتيح لك سمة Drop تحديد ما يحدث بالضبط عندما تكون البنية الخاصة بك على وشك التدمير.
يحتوي السلوك Drop على method واحدة تُسمى drop وتأخذ &mut self:
struct Connection {
id: u32,
}
impl Drop for Connection {
fn drop(&mut self) {
println!("Connection {} closed.", self.id);
}
}
لا تستدعي drop مباشرةً: تستدعي Rust ذلك automatically عندما تخرج القيمة من النطاق:
fn main() {
let conn = Connection { id: 42 };
println!("Using connection...");
} // "Connection 42 closed." تُطبع هنا تلقائيًا
سيكون الناتج:
Using connection...
Connection 42 closed.
هذه هي نسخة Rust من المُدمّر. يُستخدم عادةً لمهام التنظيف: إغلاق مقابض file، أو قطع الاتصال بالخوادم، أو تحرير الموارد التي لا يستطيع Rust إدارتها تلقائيًا. تضمن سمة Drop تشغيل كود التنظيف، حتى إذا انتهى النطاق بسبب Return مبكر.
التحدي
سهللنَبْنِ نظامًا لإدارة الموارد يوضّح التنظيف التلقائي! ستنشئ بنية FileHandle تحاكي فتح الملفات وإغلاقها؛ وعندما يخرج المقبض من النطاق، سيعلن تلقائيًا أن الملف قد تم إغلاقه.
ستنظّم شيفرتك عبر ملفين:
file_handle.rs: Define بنيةFileHandleعامة تحتوي على حقلfilenameعام (String). Implement دالة مرتبطةnewتنشئ FileHandle وتطبع message عندما يكون الملف "opened". ثم Implement السمةDropبحيث تطبع، عند إسقاط المقبض، message للإغلاق.main.rs: استورد وحدة file_handle وأنشئ دالة تُسمّىprocess_fileتتلقى filename، وتنشئ FileHandle داخل نطاق local، وتطبع message للمعالجة أثناء كون الملف "open". سيُشغَّل تطبيق Drop تلقائيًا عند انتهاء النطاق. استدعِ هذه الدالة باستخدام input المقدَّم.
عند إنشاء FileHandle، يجب أن تطبع:
Opening file: {filename}أثناء المعالجة (داخل النطاق)، اطبع:
Processing {filename}...عند إسقاط FileHandle (انتهاء النطاق)، يجب أن تطبع:
Closing file: {filename}على سبيل المثال، مع input data.txt:
Opening file: data.txt
Processing data.txt...
Closing file: data.txtومع input config.json:
Opening file: config.json
Processing config.json...
Closing file: config.jsonستتلقى input واحدًا: سلسلة filename.
تنسيق الإخراج المطلوب:
جرّب بنفسك
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);
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1الأساليب والسلوك
مقدمة في كتل التنفيذمعامل Selfالأساليب القابلة للتعديلالدوال المرتبطةكتل تنفيذ متعددةتسلسل الأساليبمراجعة - إجراءات المستطيل4مشروع: حيوان أليف افتراضي
تعريف الحيوان الأليفإطعام الحيوان الأليف2التغليف والوحدات البرمجية
أساسيات الوحدات البرمجيةالكلمة المفتاحية Publicالحقول الخاصةدوال Gettersدوال Settersمراجعة - الخزانة الآمنة5الأنواع العامة (Generics)
الـ Structs العامةالـ Methods العامةأنواع عامة متعددةالـ Functions العامةمراجعة - Coordinate Point3التعدادات المتقدمة (Advanced Enums)
التعدادات مع البياناتالأساليب (Methods) في التعداداتمطابقة حالات البياناتمراجعة التعداد Optionملخص - التعداد Shape6تعريف الـ Traits
ما هي الـ Trait؟تنفيذ الـ Traitsالتنفيذات الافتراضيةتجاوز التنفيذات الافتراضيةالـ Traits مع المعاملاتملخص - مشغل الوسائطتدرّب بنفسك: مترجم Rust عبر الإنترنت