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

Clone و Copy

جزء من قسم البرمجة كائنية التوجه في رحلة Rust على Coddy. الدرس 37 من 61.

في Rust، عندما تُسند قيمة إلى متغير آخر، تنتقل الملكية عادةً: ويصبح المتغير الأصلي غير صالح. ومع ذلك، تغيّر سمتان قياسيتان هذا السلوك: Clone وCopy.

تتيح سمة Copy النسخ الضمني على مستوى البِتّات. عندما يطبّق نوع ما Copy، فإن إسناده إلى متغير آخر ينشئ نسخة تلقائية بدلًا من نقل الملكية:

#[derive(Copy, Clone)]
struct Point {
    x: i32,
    y: i32,
}

let p1 = Point { x: 10, y: 20 };
let p2 = p1;  // p1 تم نسخه، وليس نقله

println!("{}, {}", p1.x, p2.x);  // كلاهما صالحان!

توفر سمة Clone نسخًا عميقًا explicit من خلال الطريقة .clone(). وهي مطلوبة كلما استخدمت derive Copy، ولكن يمكن استخدامها أيضًا بمفردها مع الأنواع التي تحتاج إلى نسخ explicit:

let p3 = p1.clone();  // نسخة صريحة

هناك قيد مهم: لا يمكن اشتقاق Copy إلا للأنواع التي تطبّق جميع حقولها أيضًا Copy. الأنواع البسيطة مثل الأعداد الصحيحة والأعداد العشرية هي Copy، لكن String ليست كذلك. فهي تدير ذاكرة الكومة. إذا كان الهيكل الخاص بك يحتوي على String، فلا يمكنك اشتقاق Clone إلا وليس Copy.

السمةالسلوكالاستخدام
Copyضمني، تلقائيبيانات بسيطة موجودة على المكدس فقط
Cloneصريح عبر .clone()أي بيانات قابلة للتكرار

بالنسبة إلى الهياكل البسيطة ذات الحقول البدائية، يتيح لك اشتقاق كلتا السمتين إسناد القيم بحرية دون القلق بشأن الملكية.

challenge icon

التحدي

سهل

لنَبْنِ نظام إحداثيات يوضّح الفرق بين سمتي Copy وClone! ستنشئ هيكلين، أحدهما يمكن نسخه ضمنيًا والآخر يتطلب الاستنساخ الصريح، لترى كيف يتعامل Rust مع التكرار بشكل مختلف استنادًا إلى السمات التي تشتقها.

ستنظّم شفرتك عبر ملفين:

  • coordinates.rs: عرّف هيكلين عامّين يمثّلان نوعين مختلفين من الإحداثيات:
    • GridPoint: يحتوي على الحقلين العامّين x وy (وكلاهما من النوع i32). وبما أنه يحتوي على أنواع بدائية فقط، فاشتقّ كلاً من Copy وClone حتى يمكن نسخه ضمنيًا عند إسناده.
    • NamedLocation: يحتوي على name العام (String) وحقلي x/y (من النوع i32). وبما أنه يحتوي على String، فلا يمكنك اشتقاق سوى Clone وليس Copy. سيتطلب هذا الهيكل استدعاءات صريحة لـ .clone() لإنشاء نسخة مكررة.
  • main.rs: أضف وحدة الإحداثيات الخاصة بك ووضّح كيف يتصرف كل هيكل بشكل مختلف عند تكراره. أنشئ مثيلات باستخدام المُدخلات المقدَّمة، ثم أظهر ما يلي:
    • يمكن إسناد GridPoint إلى متغير آخر، ويظل كلاهما صالحًا (نسخ ضمني)
    • يجب أن يستخدم NamedLocation.clone() لإنشاء نسخة مكررة مع الحفاظ على صلاحية النسخة الأصلية

يجب أن يُظهر ناتجك القيم الأصلية والمنسوخة/المستنسخة لإثبات أن كلا المتغيرين صالح بعد التكرار:

Original point: ({x}, {y})
Copied point: ({x}, {y})
Original location: {name} at ({x}, {y})
Cloned location: {name} at ({x}, {y})

على سبيل المثال، عند استخدام المُدخلات 5 و10 وHome:

Original point: (5, 10)
Copied point: (5, 10)
Original location: Home at (5, 10)
Cloned location: Home at (5, 10)

ستتلقى ثلاثة مُدخلات: إحداثي x (حلّله كنوع i32)، وإحداثي y (حلّله كنوع i32)، واسم الموقع.

مَطلوب تنسيق الناتج: [محتواك المترجم هنا]

جرّب بنفسك

mod coordinates;

use coordinates::{GridPoint, NamedLocation};

fn main() {
    // اقرأ المدخلات
    let mut input1 = String::new();
    std::io::stdin().read_line(&mut input1).expect("Failed to read line");
    let x: i32 = input1.trim().parse().expect("Invalid number");

    let mut input2 = String::new();
    std::io::stdin().read_line(&mut input2).expect("Failed to read line");
    let y: i32 = input2.trim().parse().expect("Invalid number");

    let mut input3 = String::new();
    std::io::stdin().read_line(&mut input3).expect("Failed to read line");
    let name = input3.trim().to_string();

    // TODO: أنشئ مثيل GridPoint باستخدام x و y

    // TODO: وضّح النسخ الضمني بالإسناد إلى متغير آخر
    // (GridPoint يطبّق Copy، لذا ينشئ هذا نسخة تلقائياً)

    // TODO: اطبع النقطة الأصلية والمنسوخة
    // Format: "Original point: ({x}, {y})"
    // التنسيق: "Copied point: ({x}, {y})"

    // TODO: أنشئ مثيل NamedLocation باستخدام name و x و y

    // TODO: وضّح الاستنساخ الصريح (NamedLocation يطبّق Clone فقط، وليس Copy)
    // استخدم .clone() لإنشاء نسخة مكررة

    // TODO: Print original and cloned location
    // Format: "Original location: {name} at ({x}, {y})"
    // Format: "Cloned location: {name} at ({x}, {y})"
}
quiz iconاختبر نفسك

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

جميع دروس البرمجة كائنية التوجه

تدرّب بنفسك: مترجم Rust عبر الإنترنت