صيغة قيود Traits
جزء من قسم البرمجة كائنية التوجه في رحلة Rust على Coddy. الدرس 40 من 61.
حتى الآن، تعلمت كيفية تعريف السمات وتنفيذها للهياكل. كما عملت مع الأنواع العامة لكتابة شيفرة مرنة. حان الوقت الآن لدمج هذه المفاهيم: استخدام السمات لتقييد أنواع البيانات التي يمكن لدالة generic acceptها.
تخيّل generic function تحتاج إلى call method محدد على معاملها. بدون أي قيود، لا يضمن Rust أن النوع T لديه ذلك method:
fn print_info<T>(item: T) {
println!("{}", item.summarize()); // خطأ! قد لا يمتلك T الدالة summarize()
}
الحل هو قيد السمة. بإضافة : TraitName بعد المعامل العام، تخبر Rust بأن T يجب أن يطبّق تلك السمة:
trait Summary {
fn summarize(&self) -> String;
}
fn print_info<T: Summary>(item: T) {
println!("{}", item.summarize()); // الآن يعرف Rust أن هذه الـ method موجودة
}
تُقرأ الصياغة <T: Summary> على أنها «T هو أي نوع يطبّق Summary». والآن لا تقبل الدالة إلا الأنواع التي have السلوك المطلوب. إذا حاولت تمرير نوع لا يطبّق Summary، فسيرفضه المصرّف مع ظهور خطأ واضح.
هذا النمط قوي لأنه يتيح لك كتابة تعليمات برمجية generic مع إمكانية الوصول إلى وظائف محددة. تظل function الخاصة بك مرنة، فهي تعمل مع any نوع، ولكن فقط مع الأنواع التي توفر السلوك الذي تحتاج إليه.
التحدي
سهللنَبْنِ نظام إشعارات يستخدم حدود السمات لضمان إمكانية إرسال الرسائل المنسّقة بشكل صحيح فقط! ستنشئ generic function تقبل أي نوع يطبّق سمة محددة، موضحًا كيفية تقييد المعاملات العامة باستخدام حدود السمات.
ستنظّم التعليمات البرمجية الخاصة بك عبر ملفين:
notification.rs: عرّف سمةNotifyمن النوع public مع method باسمmessageيأخذ&selfويعيد قيمة من النوعString. ثم أنشئ بنيتين من النوع public تطبّقان هذه السمة:Email: مع field باسمsubjectمن النوع public (String). يجب أن تعيد method الخاصة بهاmessageالقيمةEmail: {subject}SMS: مع field باسمcontentمن النوع public (String). يجب أن تعيد method الخاصة بهاmessageالقيمةSMS: {content}
send_notificationتقبل أي نوعTيطبّق السمةNotify. يجب أن تطبع هذه function result استدعاءmessage()على العنصر.main.rs: أضف وحدة الإشعارات الخاصة بك واستخدم inputs المقدّمة لإنشاء كل من instance من النوعEmailوinstance من النوعSMS. استدعِsend_notificationمع كل منهما لإظهار أن generic function الخاصة بك تعمل مع أي نوع يطبّقNotify.
الفكرة الأساسية هنا هي أن send_notification لا تعرف النوع الفعلي الذي تستقبله. إنها تعرف فقط أن النوع قادر على إنتاج message. ويضمن حد السمة T: Notify هذه القدرة.
يجب أن يُظهر الناتج إرسال الإشعارين معًا:
Email: {subject}
SMS: {content}على سبيل المثال، مع inputs Meeting Tomorrow وOn my way!:
Email: Meeting Tomorrow
SMS: On my way!ستتلقى inputين: موضوع البريد الإلكتروني ومحتوى SMS.
جرّب بنفسك
mod notification;
use notification::{Email, SMS, send_notification};
fn main() {
// قراءة المدخلات
let mut subject = String::new();
std::io::stdin().read_line(&mut subject).expect("Failed to read line");
let subject = subject.trim().to_string();
let mut content = String::new();
std::io::stdin().read_line(&mut content).expect("Failed to read line");
let content = content.trim().to_string();
// TODO: أنشئ مثيل Email باستخدام subject
// TODO: أنشئ مثيل SMS باستخدام content
// TODO: استدعِ send_notification مع email
// TODO: استدعِ send_notification مع sms
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
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 عبر الإنترنت