إرجاع الأنواع باستخدام Traits
جزء من قسم Object Oriented Programming في رحلة Rust على Coddy — الدرس 43 من 61.
لقد استخدمت قيود السمات (trait bounds) لتقييد الأنواع التي يمكن للدالة قبولها. ولكن ماذا عن ما تعيده الدالة؟ تتيح لك صيغة impl Trait تحديد أن الدالة تعيد "نوعًا ما يطبق هذه السمة" دون تسمية النوع الملموس (concrete type).
إليك بناء الجملة البرمجية قيد التنفيذ:
trait Summary {
fn summarize(&self) -> String;
}
struct Article {
headline: String,
}
impl Summary for Article {
fn summarize(&self) -> String {
self.headline.clone()
}
}
fn create_summary() -> impl Summary {
Article { headline: String::from("Breaking News!") }
}
نوع الإرجاع impl Summary يخبر المستدعين "بأنك ستحصل على شيء ينفذ Summary." يمكن للمستدعي استخدام أي طريقة من السمة (trait)، ولكنه لا يحتاج إلى معرفة أن النوع الفعلي هو Article.
هذا مفيد بشكل خاص عندما يكون النوع الملموس (concrete type) معقداً أو عندما تريد إخفاء تفاصيل التنفيذ. تَعِد الدالة بقدرة معينة (السمة - trait)، وليس بنوع محدد.
ومع ذلك، هناك قيد مهم: يجب أن تعيد الدالة نوعاً ملموساً (concrete type) واحداً بالضبط. لا يمكنك إعادة أنواع مختلفة تنفذ نفس السمة (trait) بشكل مشروط - فهذا يتطلب كائنات السمات (trait objects)، والتي ستتعلم عنها لاحقاً.
// هذا يعمل - يعيد دائماً Article
fn make_item() -> impl Summary {
Article { headline: String::from("Hello") }
}
// هذا لن يتم تجميعه - نوعان مختلفان
// fn make_item(flag: bool) -> impl Summary {
// if flag { Article { ... } } else { Tweet { ... } }
// }
التحدي
سهللنقم ببناء مصنع لبطاقات المعايدة يستخدم نوع الإرجاع impl Trait لإخفاء تفاصيل التنفيذ! ستقوم بإنشاء دالة تُرجع "شيئاً يمكنه إلقاء التحية" دون الكشف عن النوع الملموس للمستدعي.
ستقوم بتنظيم الكود الخاص بك عبر ملفين:
greetings.rs: قم بتعريف سمة (trait) عامة باسمGreetمع طريقةgreetتأخذ&selfوتُرجعString. ثم أنشئ هيكلاً (struct) باسمCard(لا يلزم أن يكون عاماً!) مع حقلmessageمن نوع (String). قم بتنفيذ سمةGreetللهيكلCard، بحيث تُرجع الرسالة. أخيراً، أنشئ دالة عامة تسمىcreate_greetingتأخذ معاملStringوتُرجعimpl Greet. يجب أن تقوم هذه الدالة بإنشاء وإرجاعCardبالرسالة المعطاة.main.rs: قم باستيراد وحدة greetings الخاصة بك واستخدم المدخلات المقدمة لاستدعاءcreate_greeting. الجمال هنا هو أن ملفك الرئيسي لا يعرف شيئاً عن النوعCardعلى الإطلاق — فهو يعرف فقط أنه تلقى شيئاً ينفذGreet. استدعِ طريقةgreetعلى القيمة المرجعة واطبع النتيجة.
البصيرة الأساسية هي أن Card يظل خاصاً بالوحدة، ولكن لا يزال بإمكان المستدعين استخدامه من خلال واجهة السمة. تَعِد الدالة بقدرة (التحية)، وليس بنوع محدد.
يجب أن يعرض مخرجك التحية:
{message}على سبيل المثال، مع المدخل Happy Birthday!:
Happy Birthday!ومع المدخل Congratulations on your promotion!:
Congratulations on your promotion!ستتلقى مدخلاً واحداً: رسالة التحية.
جرّب بنفسك
mod greetings;
use greetings::Greet;
fn main() {
// قراءة رسالة التحية من المدخلات
let mut input = String::new();
std::io::stdin().read_line(&mut input).expect("Failed to read line");
let message = input.trim().to_string();
// TODO: استدعاء create_greeting مع الرسالة
// Note: لا تعرف النوع الملموس - فقط أنه يطبق Greet!
// TODO: استدعاء الدالة greet وطباعة النتيجة
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس 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 مع المعاملاتملخص - مشغل الوسائط