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

أنواع عامة متعددة

جزء من قسم Object Oriented Programming في رحلة Rust على Coddy — الدرس 26 من 61.

أحياناً لا يكون المعامل العام الواحد كافياً. ماذا لو كنت بحاجة إلى struct يحمل قيمتين، وقد تكون هاتان القيمتان من نوعين مختلفين؟ تسمح لك لغة Rust باستخدام معاملات عامة متعددة عن طريق الفصل بينها بفاصلات.

إليك هيكل Pair الذي يحتوي على قيمتين من أنواع قد تكون مختلفة:

struct Pair<T, U> {
    first: T,
    second: U,
}

يقوم الـ <T, U> بالتصريح عن معاملي نوع مستقلين. يمكن أن يكون T و U من نفس النوع، أو مختلفين تماماً - الأمر متروك لك عند إنشاء مثيل:

let both_ints = Pair { first: 10, second: 20 };       // T=i32, U=i32
let mixed = Pair { first: "hello", second: 3.14 };    // T=&str, U=f64
let reversed = Pair { first: 100, second: "world" }; // T=i32, U=&str

عند تنفيذ الأساليب (methods)، تقوم بالتصريح عن جميع المعلمات العامة (generic parameters) في كتلة impl:

impl<T, U> Pair<T, U> {
    fn get_first(&self) -> &T {
        &self.first
    }

    fn get_second(&self) -> &U {
        &self.second
    }
}

هذا النمط شائع عندما تحتاج إلى ربط قطعتين من البيانات المرتبطة ولكن من المحتمل أن تكونا مختلفتين—مثل زوج (مفتاح-قيمة)، أو إحداثيات بأنواع رقمية مختلفة، أو نتيجة مقترنة ببيانات وصفية.

challenge icon

التحدي

سهل

لنقم ببناء نظام تخزين مفتاح-قيمة (key-value) يوضح قوة الأنواع العامة المتعددة (multiple generic types)! ستقوم بإنشاء هيكل KeyValue يمكنه الربط بين أي نوعين معاً—وهو أمر مثالي لربط العناوين بالبيانات، أو المعرفات (IDs) بالكائنات، أو أي مزيج آخر.

ستقوم بتنظيم الكود الخاص بك عبر ملفين:

  • keyvalue.rs: قم بتعريف هيكل عام عام (public generic struct) يسمى KeyValue<K, V> مع حقلين خاصين (private fields): key من النوع K و value من النوع V. قم بتنفيذ دوال (methods) للعمل مع هذا الهيكل:
    • دالة مرتبطة (associated function) تسمى new تقوم بإنشاء KeyValue من مفتاح وقيمة.
    • دالة key تعيد مرجعاً (reference) للمفتاح.
    • دالة value تعيد مرجعاً (reference) للقيمة.
    • دالة set_value تقوم باستبدال القيمة الحالية بقيمة جديدة.
  • main.rs: قم باستيراد الوحدة (module) الخاصة بك ووضح كيف يعمل نفس تعريف الهيكل مع تركيبات أنواع مختلفة. ستقوم بإنشاء أزواج مفتاح-قيمة بأنواع مختلطة لإظهار مرونة الأنواع العامة المتعددة.

في ملفك الرئيسي، قم بإنشاء والعمل مع أزواج المفتاح-القيمة التالية:

  1. زوج بمفتاح نصي (string) وقيمة عددية (integer) (المدخل الأول كمفتاح، والمدخل الثاني يتم تحويله إلى i32 كقيمة).
  2. اطبع المفتاح والقيمة.
  3. قم بتحديث القيمة إلى عدد صحيح جديد (المدخل الثالث يتم تحويله إلى i32).
  4. اطبع القيمة المحدثة.
  5. أنشئ زوجاً ثانياً بمفتاح عددي وقيمة نصية (المدخل الرابع يتم تحويله إلى i32 كمفتاح، والمدخل الخامس كقيمة).
  6. اطبع المفتاح والقيمة لهذا الزوج.

يجب أن يتبع مخرجك هذا التنسيق:

Key: {key}, Value: {value}
Updated value: {value}
Key: {key}, Value: {value}

على سبيل المثال، مع المدخلات name، و 42، و 100، و 7، و lucky:

Key: name, Value: 42
Updated value: 100
Key: 7, Value: lucky

لاحظ كيف يستخدم الزوج الأول KeyValue<String, i32> بينما يستخدم الثاني KeyValue<i32, String>—نفس الهيكل، ولكن بتركيبات أنواع مختلفة!

ستتلقى خمسة مدخلات: مفتاح نصي، قيمة عددية، عدد صحيح بديل، مفتاح عددي، وقيمة نصية.

جرّب بنفسك

mod keyvalue;

use keyvalue::KeyValue;

fn main() {
    // قراءة خمسة مدخلات
    let mut input1 = String::new();
    std::io::stdin().read_line(&mut input1).expect("Failed to read line");
    let string_key = input1.trim().to_string();

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

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

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

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

    // TODO: إنشاء زوج KeyValue<String, i32> باستخدام string_key و int_value

    // TODO: طباعة المفتاح والقيمة بالتنسيق: "Key: {key}, Value: {value}"

    // TODO: تحديث القيمة باستخدام set_value مع replacement_int

    // TODO: طباعة القيمة المحدثة بالتنسيق: "Updated value: {value}"

    // TODO: إنشاء زوج KeyValue<i32, String> باستخدام int_key و string_value

    // TODO: طباعة المفتاح والقيمة لهذا الزوج بالتنسيق: "Key: {key}, Value: {value}"
}
quiz iconاختبر نفسك

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

جميع دروس Object Oriented Programming