الانتقال إلى المحتوى الرئيسي
الوحدة 3 · الدرس 1 من 25/14 في الدورة~15 min
دروس الوحدة (1/2)

قواعد الملكية

الملكية هي الميزة الأكثر تميزًا في Rust. فهو يسمح للغة بضمان سلامة الذاكرة دون الحاجة إلى أداة تجميع البيانات المهملة أو إجبارك على إلغاء تخصيص ذاكرة الكومة يدويًا (كما هو الحال في C أو C++).

القواعد الثلاثة للملكية

تخضع إدارة الذاكرة في Rust لثلاث قواعد بسيطة يتم فحصها بدقة بواسطة المترجم:

  1. كل قيمة في Rust لها متغير يسمى مالكها.
  2. لا يمكن أن يكون هناك سوى مالك واحد في كل مرة.
  3. عندما يخرج المالك عن النطاق، يتم إسقاط القيمة تلقائيًا.

المكدس مقابل الكومة

لفهم الملكية، من المهم معرفة مكان وجود البيانات:

  • المكدس: يخزن البيانات ذات الحجم الثابت المعروفة في وقت الترجمة (على سبيل المثال، الأعداد الصحيحة والقيم المنطقية). الوصول سريع للغاية.
  • الكومة: تخزن بيانات ذات حجم ديناميكي غير معروفة في وقت الترجمة (على سبيل المثال، String). التخصيص أبطأ ويتطلب وجود مؤشر مخزن على المكدس.

مفهوم "التحرك"

عندما نقوم بتعيين متغير مخصص للكومة إلى متغير آخر، ينقل Rust ** (أو ينقل) ملكية القيمة، مما يؤدي إلى إبطال المتغير الأول:

Rust
let s1 = String::from("ciao");
let s2 = s1; // Ownership of the text moves to s2. s1 is NO longer usable!

// println!("{}", s1); // COMPILATION ERROR! s1 is "borrow of moved value"
println!("{}", s2); // Valid!

يتجنب هذا السلوك "الخطأ الحر المزدوج" (محاولة تحرير نفس الذاكرة مرتين عند الخروج عن النطاق)، نظرًا لأن s2 فقط هو الذي سيحرر الذاكرة.

مفهوم "الاستنساخ" (نسخة عميقة)

إذا أردنا صراحةً نسخ محتويات String بالكامل (كل من مؤشرات المكدس وبيانات النص الفعلية في الكومة)، فيمكننا استخدام الطريقة .clone(). يؤدي هذا إلى تكرار البيانات الموجودة في الكومة بشكل كامل، مع الحفاظ على صلاحية كل من المتغير الأصلي والمتغير الجديد، على حساب عبء الأداء لتخصيص الذاكرة الجديدة:

Rust
let s1 = String::from("ciao");
let s2 = s1.clone(); // Deep copy. Both variables remain valid!
println!("s1: {}, s2: {}", s1, s2);

مفهوم "النسخة"

بالنسبة للأنواع البسيطة المخزنة بالكامل على المكدس (مثل الأعداد الصحيحة i32، والقيم المنطقية bool، والأحرف char)، تنفذ المهمة **نسخة سطحية تلقائية ** فعلية، مما يعني أن كلا المتغيرين يظلان صالحين:

Rust
let x = 5;
let y = x; // Copies the value 5 onto the stack. Both variables are usable!
println!("x: {}, y: {}", x, y); // Valid!

جربه بنفسك

تمرين#rust.m3.l1.e1
المحاولات: 0جارٍ التحميل…

قم بتعريف سلسلة s1 تحتوي على النص "مرحبًا". قم بتعيين s1 إلى s2 (لنقل الملكية). أخيرًا، قم بطباعة s2 باستخدام println!.

جارٍ تحميل المحرر…
إظهار التلميح

استخدم `let s2 = s1;` لنقل الملكية إلى `s2` وطباعتها باستخدام `println!('{}', s2);`.

الحل متاح بعد 3 من المحاولات

تمرين#rust.m3.l1.e2
المحاولات: 0جارٍ التحميل…

قم بتعريف متغير عدد صحيح x بقيمة 5. قم بتعيين x إلى y (إجراء نسخة). وأخيرًا، قم بطباعة كل من x وy في نفس println! إفادة.

جارٍ تحميل المحرر…
إظهار التلميح

افعل `let y = x;` ثم اطبع كلا القيمتين، على سبيل المثال، `println!('{} {}', x, y);`.

الحل متاح بعد 3 من المحاولات

تمرين#rust.m3.l1.e3
المحاولات: 0جارٍ التحميل…

Declare a String s1 with the value "Rust". Create a deep copy of s1 in a new variable s2 using the clone method. Finally, print both s1 and s2 separated by a space using the println! macro.

جارٍ تحميل المحرر…
إظهار التلميح

Use `let s2 = s1.clone();` to deep copy the value of `s1` into `s2`, then print them with `println!("{} {}", s1, s2);`.

الحل متاح بعد 3 من المحاولات