محتويات الدورة

Rust / المتقدم / الدرس 13

المؤشرات الذكية والتعديل الداخلي

اختر الملكية المنفردة والمشتركة والوصول المفحوص ديناميكيًا بوضوح، وميّز التنظيف والدورات المرجعية من ضمانات الذاكرة.

وقت القراءة التقريبي: 4 دقيقةتاريخ مراجعة المحتوى
في هذه الصفحة

أهداف الدرس

  • مقارنة Box وRc وWeak وCell وRefCell.
  • شرح حراس استعارة RefCell وأساليب الاستعارة القابلة للفشل.
  • تجنب دورات المالكين والملكية المشتركة الزائدة.

اختيار أبسط نموذج عمر

تكفي قيمة محلية مملوكة غالبًا. تمنح Box<T> ملكية حصرية لتخصيص وتدعم البنى العودية أو قيمًا ديناميكية الحجم خلف مؤشر. تدعم Rc<T> مالكين في خيط واحد بعد مرجعي غير ذري. تراقب Weak دون إبقاء القيمة وتكسر الدورات. تحل المقابض الملكية لا التعديل الاعتباطي. إذا كفت استعارة مؤقتة فقد يزيد العد التعقيد دون فائدة. ارسم شبكة الملكية منفصلة عن الوصول كي لا يصير كل رابط خلفي مالكًا.

تركيب الملكية المشتركة والتعديل المفحوص

تتيح RefCell<T> تعديلًا داخليًا مع فحص الاستعارة أثناء التنفيذ. تجمع Rc<RefCell<T>> ملكية مشتركة داخل خيط وتعديلًا مضبوطًا. يستنسخ المثال مقبض Rc لا محتويات المتجه. يلحق حارس قابل للتعديل عنصرًا وينتهي عند العبارة قبل قراءة مشتركة. يرى الأصل المتجه نفسه. يفيد ذلك بعض الشبكات وردود النداء ولا ينبغي أن يكون افتراضي كل حقل. لا تجعل RefCell التعديل المشترك آمنًا بين الخيوط.

rust مقبضان ومتجه واحد
use std::cell::RefCell;
use std::rc::Rc;
fn main() {
    let original = Rc::new(RefCell::new(vec![1u32]));
    let shared = Rc::clone(&original);
    shared.borrow_mut().push(2);
    println!("{}", original.borrow().len());
}
الناتج المتوقع
2

يملك المقبضان RefCell نفسها، ويظهر الإلحاق عبر الأصل بعد انتهاء الحارس القابل للتعديل.

الحارس يبقي الاستعارة الديناميكية نشطة

قد تسبب borrow وborrow_mut حالة panic عند خرق القاعدة. وتبلغ try_borrow وtry_borrow_mut عن فشل قابل للمعالجة. يبقي المثال حارسًا مشتركًا ويؤكد تعذر الوصول الحصري ثم يسقطه قبل التعديل. لا يلزم وصول فاسد أو panic لشرح التعارض. قد تسبب الحراسة عبر رد نداء فشل استعارة عند إعادة الدخول، فقصّر نطاقها. الفحص يمنع إنشاء المراجع المتعارضة عبر الواجهة الآمنة ولا يسمح بها معًا.

rust ملاحظة التعارض دون panic
use std::cell::RefCell;
fn main() {
    let value = RefCell::new(4u32);
    let read = value.borrow();
    println!("{}", value.try_borrow_mut().is_err());
    drop(read);
    *value.borrow_mut() = 9;
    println!("{}", value.borrow());
}
الناتج المتوقع
true
9

يمنع الحارس المشترك التعديل، ويسمح إسقاطه بتحديث حصري ثم تقرأ مراقبة جديدة تسعة.

أمان الذاكرة لا يضمن غياب التسرب

قد تبقي دورة Rc كل العدادات القوية فوق صفر فتسرب القيم في Rust الآمنة. استخدم Weak للرابط المراقب ثم upgrade ومعالجة None عند الانتهاء. يحدث الإتلاف حين تحرر بنية الملكية القيمة فعلًا لا حين تبدو الشبكة غير قابلة للوصول. تدعم Drop التنظيف وينبغي تجنب panic أثناء الفك. وقد يمنع mem::forget أو توقف العملية الإتلاف. لا تبنِ افتراض أمان unsafe على تشغيل كل مستدعٍ آمن للمدمّر دائمًا.

مقارنة نماذج التعديل بالتزاماتها

تدعم Cell استبدال قيم بطرق لا تسلم مراجع مشتركة عادية لداخلها، وتدعم RefCell حراسًا ديناميكيين. تعالج Mutex أنواع متطلبات عبر الخيوط لاحقًا. تكفي Rc أو Arc للبيانات المشتركة الثابتة دون خلية أو قفل. فضّل إعادة تنظيم الملكية إذا أزالت فئة فحوص كاملة. اختبر إعادة الدخول وانتهاء المراقبين وعدّ التنظيف اصطناعيًا. قد يبقى البرنامج آمنًا مع panic أو تسرب أو ترتيب تحديث خاطئ، فاختبرها مستقلة.

الأخطاء الشائعة وإصلاحها

panic من RefCell داخل رد نداء متداخل.

لماذا يحدث؟
بقي حارس متعارض أثناء إعادة الدخول.
كيف تصلحه؟
أسقط الحراس قبل الرد أو أعد ترتيب التحديث.
كيف تتجنب تكراره؟
قصّر نطاقات الاستعارة الديناميكية.

مقابض Rc مستنسخة تشارك التغييرات.

لماذا يحدث؟
استنساخ المقبض لم يستنسخ القيمة الأساسية.
كيف تصلحه؟
أنشئ قيمة مملوكة منفصلة للقطة مستقلة.
كيف تتجنب تكراره؟
اذكر هل تشارك الواجهة الهوية أم تنسخ البيانات.

شبكة Rc لا تحرر مواردها.

لماذا يحدث؟
تشكل روابط الملكية القوية دورة.
كيف تصلحه؟
استخدم رابط Weak مناسبًا وافحص upgrade.
كيف تتجنب تكراره؟
راجع دورات الملكية مستقلة عن الوصول.

اختبر فهمك

1. استبدل Rc::clone بمتجه مستنسخ مستقل داخل RefCell جديدة، واشرح تغير الطول المرصود عبر الأصل.

اعرض الحل المشروح

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

2. تملك عقدتان بعضهما بـRc وتُسقط المقابض الخارجية. اشرح الإصلاح وطريقة مراقبة الرابط الخلفي بعده.

اعرض الحل المشروح

استبدل الرابط غير المالك منطقيًا بـWeak. يسمح حذف المالكين الخارجيين بإسقاط عقدة وتحرير رابطها للأخرى. يستدعي المراقب upgrade ويعالج None بدل افتراض بقاء الهدف. يجب أن يتبع اتجاه الضعف نموذج الملكية لا مجرد إنجاح اختبار.

أهم ما تعلمته

  • افصل الملكية المشتركة عن سياسة التعديل.
  • تفرض الحراسة الديناميكية حصرية الوصول.
  • راجع الدورات وإعادة الدخول والتنظيف منفصلة.

المراجع الرسمية