قيود متعددة
جزء من قسم 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.
التحدي
سهللنقم ببناء نظام فحص للمنتجات يتطلب أن تمتلك العناصر قدرات متعددة! ستقوم بإنشاء دالة عامة (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) الخاصة بك
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1الأساليب والسلوك
مقدمة في كتل التنفيذمعامل Selfالأساليب القابلة للتعديلالدوال المرتبطةكتل تنفيذ متعددةتسلسل الأساليبمراجعة - إجراءات المستطيل4مشروع: حيوان أليف افتراضي
تعريف الحيوان الأليفإطعام الحيوان الأليف2التغليف والوحدات البرمجية
أساسيات الوحدات البرمجيةالكلمة المفتاحية Publicالحقول الخاصةدوال Gettersدوال Settersمراجعة - الخزانة الآمنة5الأنواع العامة (Generics)
الـ Structs العامةالـ Methods العامةأنواع عامة متعددةالـ Functions العامةمراجعة - Coordinate Point8Traits كقيود
صيغة قيود Traitsقيود متعددةجملة Whereإرجاع الأنواع باستخدام Traitsمراجعة - طابعة Generic3التعدادات المتقدمة (Advanced Enums)
التعدادات مع البياناتالأساليب (Methods) في التعداداتمطابقة حالات البياناتمراجعة التعداد Optionملخص - التعداد Shape6تعريف الـ Traits
ما هي الـ Trait؟تنفيذ الـ Traitsالتنفيذات الافتراضيةتجاوز التنفيذات الافتراضيةالـ Traits مع المعاملاتملخص - مشغل الوسائط