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

الـ Structs العامة

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

حتى الآن، كان لكل struct قمت بإنشائه حقول ذات أنواع محددة وملموسة. يمتلك Pet اسماً من نوع String، ويمتلك Rectangle أبعاداً من نوع f64. ولكن ماذا لو أردت إنشاء struct يمكنه الاحتفاظ بـ أي نوع من البيانات؟

هذا هو المكان الذي تبرز فيه أهمية الأنواع العامة (generics). تتيح لك الأنواع العامة كتابة كود مرن وقابل لإعادة الاستخدام يعمل مع أنواع متعددة. فبدلاً من تحديد نوع معين بشكل ثابت، يمكنك استخدام عنصر نائب — عادةً ما يكون T — يتم استبداله بنوع ملموس عند استخدام الـ struct.

إليك هيكل تغليف (wrapper struct) بسيط يمكنه حمل أي نوع:

struct Wrapper<T> {
    value: T,
}

يصرح الـ <T> بعد اسم الـ struct عن معلمة نوع عام (generic type parameter). داخل الـ struct، يعمل T كبديل لأي نوع ستستخدمه بالفعل. عندما تقوم بإنشاء مثيل (instance)، يستنتج Rust النوع الملموس (concrete type):

let int_wrapper = Wrapper { value: 42 };        // T هي i32
let float_wrapper = Wrapper { value: 3.14 };    // T هي f64
let text_wrapper = Wrapper { value: "hello" };  // T هي &str

كل واحد من هذه هو نوع ملموس مختلف—Wrapper<i32>، و Wrapper<f64>، و Wrapper<&str>—لكنها جميعاً تشترك في نفس تعريف الـ struct. هذا يلغي الحاجة إلى كتابة هياكل IntWrapper و FloatWrapper و StringWrapper منفصلة تقوم بنفس الشيء جوهرياً.

الحرف T هو مجرد اصطلاح (اختصار لكلمة "Type"). يمكنك استخدام أي معرف (identifier) صالح، ولكن T هو المعيار في Rust ومعظم اللغات الأخرى التي تدعم الأنماط العامة (generics).

challenge icon

التحدي

سهل

لنقم ببناء حاوية عامة (generic container) يمكنها الاحتفاظ بأي نوع من القيم! ستقوم بإنشاء هيكل Container يوضح كيف تجعل القوالب العامة (generics) كودك مرناً وقابلاً لإعادة الاستخدام.

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

  • container.rs: قم بتعريف هيكل عام عام (public generic struct) يسمى Container<T> مع حقل عام واحد item من النوع T. يجب أن تكون هذه الحاوية قادرة على الاحتفاظ بأي نوع—أعداد صحيحة، أعداد عشرية، نصوص، أو أي شيء آخر.
  • main.rs: قم باستيراد وحدة الحاوية الخاصة بك وأظهر مرونتها من خلال إنشاء حاويات تحتفظ بأنواع مختلفة من البيانات. ستقوم بإنشاء ثلاث حاويات وعرض ما تحتويه كل واحدة منها.

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

  1. حاوية تحتوي على قيمة عدد صحيح (المدخل الأول، يتم تحليله كـ i32)
  2. حاوية تحتوي على قيمة عدد عشري (المدخل الثاني، يتم تحليله كـ f64)
  3. حاوية تحتوي على نص (المدخل الثالث، يتم الاحتفاظ به كـ String)

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

Integer container: {value}
Float container: {value}
String container: {value}

على سبيل المثال، مع المدخلات 42 و 3.14 و hello:

Integer container: 42
Float container: 3.14
String container: hello

لاحظ كيف يعمل نفس تعريف Container<T> لجميع الأنواع الثلاثة المختلفة—هذه هي قوة القوالب العامة (generics)!

ستتلقى ثلاثة مدخلات: قيمة عدد صحيح، وقيمة عدد عشري، وقيمة نصية.

ورقة مرجعية

تسمح لك الأنواع العامة (Generics) بإنشاء هياكل (structs) يمكنها الاحتفاظ بأي نوع من البيانات باستخدام عنصر نائب لمعلمة النوع (type parameter placeholder).

للتصريح عن هيكل عام (generic struct)، استخدم الأقواس الزاوية مع معلمة نوع (يُصطلح عليها عادةً بـ T):

struct Wrapper<T> {
    value: T,
}

يقوم <T> بالتصريح عن معلمة نوع عامة، ويعمل T داخل الهيكل كعنصر نائب للنوع الفعلي.

عند إنشاء مثيلات (instances)، يستنتج Rust النوع الملموس (concrete type):

let int_wrapper = Wrapper { value: 42 };        // T هو i32
let float_wrapper = Wrapper { value: 3.14 };    // T هو f64
let text_wrapper = Wrapper { value: "hello" };  // T هو &str

يصبح كل مثيل نوعاً ملموساً مختلفاً (Wrapper<i32>، Wrapper<f64>، Wrapper<&str>) مع مشاركة نفس تعريف الهيكل.

جرّب بنفسك

mod container;

use container::Container;

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

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

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

    // TODO: إنشاء ثلاث حاويات باستخدام Container<T>
    // 1. حاوية أعداد صحيحة تحتوي على int_value
    // 2. حاوية أعداد عشرية تحتوي على float_value
    // 3. حاوية نصوص تحتوي على string_value

    // TODO: طباعة محتويات كل حاوية بالتنسيق المطلوب
    // Integer container: {value}
    // Float container: {value}
    // String container: {value}
}
quiz iconاختبر نفسك

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

جميع دروس Object Oriented Programming