قيود متعددة
جزء من قسم البرمجة كائنية التوجه في رحلة Rust على Coddy. الدرس 41 من 61.
أحيانًا لا تكون سمة واحدة كافية. قد تحتاج إلى نوع generic يمكنه أن يُطبع و أن يوفّر ملخصًا. تتيح لك Rust طلب سمات متعددة باستخدام الصيغة +.
إليك كيفية تحديد أن نوعًا ما يجب أن يطبّق سمتين:
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." داخل الدالة، يمكنك استخدام القدرات من كلتا السمتين: الطباعة باستخدام {} (من Display) واستدعاء summarize() (من Summary).
يمكنك ربط أي عدد تحتاج إليه من السمات:
fn process<T: Display + Summary + Clone>(item: T) {
// يمكن الطباعة والتلخيص والاستنساخ
}
هذا النمط أساسي عندما تعتمد function الخاصة بك على سلوكيات متعددة. وبدلاً من قبول أي نوع والأمل في أن يعمل، فإنك تعلن صراحةً عن capabilities المطلوبة بالضبط، ويفرض المترجم ذلك في وقت الترجمة.
التحدي
سهللنبنِ نظامًا لفحص المنتجات يتطلب أن تتمتع العناصر بقدرات متعددة! ستنشئ دالة generic لا تقبل إلا الأنواع التي تطبق كلًا من trait مخصص وtrait قياسي، موضحًا كيف تجمع صيغة + بين حدود متعددة.
ستنظم الكود الخاص بك عبر ملفين:
product.rs: Define trait عامًا باسمInspectableمع method تسمىinspectتأخذ&selfوتُرجعStringتحتوي على تفاصيل الفحص. ثم أنشئ struct عامًا باسمGadgetمع الحقلين العامينname(String) وserial(u32). يجب أن يطبق Gadget كلًا منInspectable(مع إرجاعInspecting: {name}) وstd::fmt::Display(مع التنسيق بالشكل{name} (SN: {serial})). وأخيرًا، أنشئ دالة generic عامة تسمىfull_reportتقبل أي نوعTيطبق كلًا منDisplayوInspectable. يجب أن تطبع هذه الدالة سطرين: العنصر أولًا باستخدام منسق{}، ثم نتيجة استدعاءinspect().main.rs: استورد module الخاص بالمنتج وأنشئ instance منGadgetباستخدام inputs المقدمة. استدعِfull_reportمع gadget الخاص بك لإظهار أنه يستوفي متطلبات trait كليهما.
تكمن قوة الحدود المتعددة في أن دالة full_report الخاصة بك يمكنها استخدام capabilities من كلا traitين، فتعرض العنصر بطريقة أنيقة وتحصل أيضًا على تفاصيل الفحص، وكل ذلك مضمون أثناء compile time.
يجب أن يُظهر output كلاً من تنسيق العرض ونتيجة الفحص:
{name} (SN: {serial})
Inspecting: {name}على سبيل المثال، مع inputs Smartwatch و98765:
Smartwatch (SN: 98765)
Inspecting: Smartwatchستتلقى inputين: اسم gadget ورقم serial (قم بتحليله كـ u32).
جرّب بنفسك
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: أنشئ مثيل Gadget بالاسم والرقم التسلسلي
// TODO: استدعِ full_report مع الـ gadget الخاص بك
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
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 مع المعاملاتملخص - مشغل الوسائطتدرّب بنفسك: مترجم Rust عبر الإنترنت