0Pricing
Learn Rust Coding · درس

القابلية الداخلية للتغيير: RefCell وCell

تعلّموا عن `RefCell` و`Cell` للقابلية الداخلية للتغيير، بما يتيح الوصول القابل للتغيير إلى البيانات عبر مرجع غير قابل للتغيير بأمان.

القابلية الداخلية للتغيير: RefCell وCell درس مجاني في Learn Rust Coding على CoddyKit. هذا هو الدرس 2 من أصل 3. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Learn Rust Coding، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Learn Rust Coding 3 دروس في المجموع.

ما قابلية التغيير الداخلية؟

تمنعكم قواعد الاستعارة في Rust عادةً من امتلاك مرجع قابل للتغيير إلى البيانات إذا كان لديكم مرجع غير قابل للتغيير إليها مسبقًا. ويضمن ذلك أمان البيانات.

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

`Cell<T>`: لأنواع Copy

يوفّر النوع Cell<T> قابلية التغيير الداخلية للأنواع التي تطبّق السمة Copy، مثل الأعداد والقيم المنطقية والمحارف. ويعمل ذلك من خلال استبدال القيمة الموجودة داخله.

  • get(): يعيد نسخة من القيمة الموجودة داخل Cell.
  • set(value): يستبدل القيمة الموجودة داخل Cell بقيمة جديدة.

وهو بسيط وفعّال للبيانات الصغيرة القابلة للنسخ.

استخدام `Cell` لتحديث القيم

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

use std::cell::Cell;

fn main() {
  let my_num = Cell::new(10);
  println!("Initial value: {}", my_num.get());

  my_num.set(20);
  println!("Updated value: {}", my_num.get());

  let x = &my_num;
  x.set(30); // Still works via immutable reference!
  println!("Via immutable ref: {}", my_num.get());
}

`RefCell<T>`: للأنواع غير القابلة للنسخ

عندما تحتاجون إلى قابلية التغيير الداخلية لأنواع لا تطبّق Copy، مثل String أو Vec أو البنى المخصصة، تستخدمون RefCell<T>.

يتيح RefCell الحصول على مراجع قابلة للتغيير إلى البيانات الداخلية، لكنه يفرض قواعد الاستعارة في Rust وقت التشغيل، لا وقت الترجمة.

الاستعارة وقت التشغيل في `RefCell`

يوفّر RefCell أساليب تعيد مؤشرات ذكية:

  • borrow(): يعيد Ref (مؤشرًا ذكيًا غير قابل للتغيير). يمكنكم إجراء عدة استعارات غير قابلة للتغيير في الوقت نفسه.
  • borrow_mut(): يعيد RefMut (مؤشرًا ذكيًا قابلًا للتغيير). لا يمكنكم إجراء أكثر من استعارة واحدة قابلة للتغيير في الوقت نفسه.

إذا خالفتم هذه القواعد وقت التشغيل، فسيتسبب برنامجكم في panic!.

استخدام `RefCell` (استعارة غير قابلة للتغيير)

نستخدم هنا borrow() للحصول على مرجع غير قابل للتغيير إلى String الموجودة داخل RefCell. ويمكننا طباعة محتواها.

use std::cell::RefCell;

fn main() {
  let my_string_cell = RefCell::new(String::from("Hello"));

  let s1 = my_string_cell.borrow();
  println!("Value: {}", *s1); // Dereference Ref to get String

  let s2 = my_string_cell.borrow(); // Multiple immutable borrows are fine
  println!("Another value: {}", *s2);
}

استخدام `RefCell` (استعارة قابلة للتغيير)

لنحصل الآن على مرجع قابل للتغيير باستخدام borrow_mut(). يتيح لنا ذلك تعديل String. لاحظوا أنه بمجرد دخول s_mut إلى النطاق، لا يُسمح بأي استعارات أخرى، قابلة للتغيير أو غير قابلة للتغيير.

use std::cell::RefCell;

fn main() {
  let my_string_cell = RefCell::new(String::from("World"));

  { // Scope for the mutable borrow
    let mut s_mut = my_string_cell.borrow_mut();
    s_mut.push_str(", Rust!");
  }
  // s_mut is out of scope here, so we can borrow again

  let s_final = my_string_cell.borrow();
  println!("Final value: {}", *s_final);
}

حالة الذعر وقت التشغيل في `RefCell`

إذا حاولتم الحصول على استعارة قابلة للتغيير أثناء وجود استعارة أخرى قابلة للتغيير (أو أي استعارة غير قابلة للتغيير) نشطة، فسيتسبب RefCell في panic! لبرنامجكم وقت التشغيل. ويمنع ذلك تلف البيانات.

شغّلوا هذه الشيفرة لرؤية ذلك عمليًا! ستتعطل مع ظهور خطأ «الاستعارة قيد الاستخدام مسبقًا».

use std::cell::RefCell;

fn main() {
  let my_value = RefCell::new(vec![1, 2, 3]);

  let _first_mut_borrow = my_value.borrow_mut();
  println!("First mutable borrow is active.");

  // This line will cause a runtime panic!
  // Try commenting it out to see the program run successfully.
  let _second_mut_borrow = my_value.borrow_mut();

  println!("This line will not be reached.");
}

ملخص `Cell` في مقابل `RefCell`

يعتمد الاختيار بين Cell وRefCell على نوع بياناتكم وكيفية تفاعلكم معها:

  • Cell<T>: استخدموه للأنواع التي تطبّق Copy. فهو يستبدل القيمة بأكملها، ويكون عادةً أبسط وأكثر أداءً.
  • RefCell<T>: استخدموه للأنواع التي لا تطبّق Copy. فهو يوفّر مراجع إلى البيانات الداخلية ويفرض قواعد الاستعارة وقت التشغيل، ما يتيح تغييرات أكثر تعقيدًا.

اختبار سريع: Cell أم RefCell؟

لديكم struct يحتاج إلى تخزين عدّاد قابل للتغيير (u32) وقائمة أسماء قابلة للتغيير (Vec<String>)، ويجب تحديث كليهما من خلال مرجع غير قابل للتغيير إلى struct. ما نوعا قابلية التغيير الداخلية اللذان ستستخدمونهما لكل حقل؟

مراجعة: قابلية التغيير الداخلية

تعلّمتم نمط قابلية التغيير الداخلية في Rust، الذي يتيح تعديل البيانات من خلال مرجع غير قابل للتغيير بطريقة مضبوطة وآمنة.

  • Cell<T>: للأنواع Copy، ويستبدل القيمة الداخلية.
  • RefCell<T>: للأنواع غير القابلة لـCopy، ويوفّر مراجع قابلة للتغيير وغير قابلة للتغيير مع التحقق منها وقت التشغيل.
  • تؤدي مخالفة قواعد RefCell إلى حالة ذعر وقت التشغيل، ما يضمن الأمان.

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

الأسئلة الشائعة

هل درس «القابلية الداخلية للتغيير: RefCell وCell» مجاني؟

نعم — نص درس «القابلية الداخلية للتغيير: RefCell وCell» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Learn Rust Coding، انتقل إلى CoddyKit PRO. تتضمن دورة Learn Rust Coding 3 دروس في المجموع.

ماذا ستتعلم في «القابلية الداخلية للتغيير: RefCell وCell»؟

تعلّموا عن `RefCell` و`Cell` للقابلية الداخلية للتغيير، بما يتيح الوصول القابل للتغيير إلى البيانات عبر مرجع غير قابل للتغيير بأمان. تتمرن على Learn Rust Coding مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Learn Rust Coding؟

لا تُشترط خبرة سابقة. Learn Rust Coding على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 3.

كم من الوقت يستغرق درس «القابلية الداخلية للتغيير: RefCell وCell»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Learn Rust Coding هذا؟

نعم. كل درس في Learn Rust Coding يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. المؤشرات الذكية Box وRc وArc
  2. القابلية الداخلية للتغيير: RefCell وCell
  3. التزامن الآمن مع الخيوط
← العودة إلى Learn Rust Coding