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

قيود متعددة

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

أحيانًا لا يكون قيد السمة (trait bound) الواحد كافيًا. قد تحتاج إلى نوع عام (generic type) يمكن طباعته وتقديم ملخص في آن واحد. تسمح لك لغة Rust بطلب سمات متعددة باستخدام بناء الجملة +.

إليك كيفية تحديد أن النوع يجب أن يطبق سمتين (traits):

use std::fmt::Display;

trait Summary {
    fn summarize(&self) -> String;
}

fn announce<T: Display + Summary>(item: T) {
    println!("Breaking news: {}", item);
    println!("Summary: {}", item.summarize());
}

القيد T: Display + Summary يعني أن "T يجب أن يطبق كلاً من Display و Summary." داخل الدالة، يمكنك استخدام القدرات من كلا السمتين (traits)—الطباعة باستخدام {} (من Display) واستدعاء summarize() (من Summary).

يمكنك ربط عدد من السمات (traits) حسب الحاجة:

fn process<T: Display + Summary + Clone>(item: T) {
    // يمكنه الطباعة، والتلخيص، والاستنساخ
}

هذا النمط ضروري عندما تعتمد الـ function الخاصة بك على سلوكيات متعددة. فبدلاً من قبول أي type والأمل في أن يعمل، فإنك تعلن صراحةً عن القدرات المطلوبة بالضبط - ويقوم الـ compiler بفرض ذلك في الـ compile time.

challenge icon

التحدي

سهل

لنقم ببناء نظام فحص للمنتجات يتطلب أن تمتلك العناصر قدرات متعددة! ستقوم بإنشاء دالة عامة (generic function) تقبل فقط الأنواع التي تُنفذ كلاً من سمة (trait) مخصصة وسمة قياسية، مما يوضح كيف تجمع صيغة + بين قيود متعددة.

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

  • product.rs: قم بتعريف سمة Inspectable عامة (public) مع دالة تسمى inspect تأخذ &self وتعيد String يحتوي على تفاصيل الفحص. ثم أنشئ هيكل Gadget عام مع حقول عامة name (String) و serial (u32). يجب أن يقوم Gadget بتنفيذ كل من Inspectable (بحيث يعيد "Inspecting: {}") و std::fmt::Display (بتنسيق مثل "{} (SN: {})"). أخيرًا، أنشئ دالة عامة تسمى full_report تقبل أي نوع T يُنفذ كلاً من Display و Inspectable. يجب أن تطبع هذه الدالة سطرين: الأول هو العنصر باستخدام منسق {}، ثم نتيجة استدعاء inspect().
  • main.rs: قم باستيراد وحدة المنتج (product module) وأنشئ مثيلاً من Gadget باستخدام المدخلات المقدمة. استدعِ full_report مع الأداة (gadget) الخاصة بك لإظهار أنها تستوفي متطلبات كلتا السمتين.

تكمن قوة القيود المتعددة في أن دالة full_report الخاصة بك يمكنها استخدام القدرات من كلتا السمتين — عرض العنصر بشكل جيد والحصول على تفاصيل الفحص — وكل ذلك مضمون في وقت التجميع (compile time).

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

{name} (SN: {serial})
Inspecting: {name}

على سبيل المثال، مع المدخلات Smartwatch و 98765:

Smartwatch (SN: 98765)
Inspecting: Smartwatch

ستتلقى مدخلين: اسم الأداة (gadget name) والرقم التسلسلي (قم بتحليله كـ u32).

ورقة مرجعية

يمكنك طلب قيود سمات (trait bounds) متعددة على نوع عام باستخدام بناء الجملة +:

fn function_name<T: Trait1 + Trait2>(item: T) {
    // Can use capabilities from both traits
}

مثال مع Display وسمة مخصصة:

use std::fmt::Display;

trait Summary {
    fn summarize(&self) -> String;
}

fn announce<T: Display + Summary>(item: T) {
    println!("Breaking news: {}", item);
    println!("Summary: {}", item.summarize());
}

يمكنك ربط سمات متعددة حسب الحاجة:

fn process<T: Display + Summary + Clone>(item: T) {
    // Can print, summarize, AND clone
}

يفرض المترجم (compiler) أن النوع ينفذ جميع السمات المحددة في وقت الترجمة (compile time).

جرّب بنفسك

mod product;

use product::{Gadget, full_report};

fn main() {
    // قراءة المدخلات
    let mut name = String::new();
    std::io::stdin().read_line(&mut name).expect("Failed to read line");
    let name = name.trim().to_string();
    
    let mut serial_input = String::new();
    std::io::stdin().read_line(&mut serial_input).expect("Failed to read line");
    let serial: u32 = serial_input.trim().parse().expect("Failed to parse serial");
    
    // TODO: قم بإنشاء مثيل (instance) من Gadget باستخدام الاسم والرقم التسلسلي
    
    // TODO: قم باستدعاء full_report مع الأداة (gadget) الخاصة بك
}
quiz iconاختبر نفسك

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

جميع دروس Object Oriented Programming