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

التنفيذات الافتراضية

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

حتى الآن، كان كل أسلوب سمة (trait method) قمنا بتعريفه مجرد توقيع—متطلب بدون جسم. ولكن ماذا لو كانت معظم الأنواع التي تطبق سمة ما ستستخدم نفس المنطق؟ تتيح لك Rust توفير تنفيذ افتراضي مباشرة في تعريف السمة.

بدلاً من إنهاء توقيع الدالة بفاصلة منقوطة، يمكنك إضافة جسم للدالة:

trait Greet {
    fn greet(&self) -> String {
        String::from("Hello there!")
    }
}

الآن، أي نوع يقوم بتنفيذ Greet يحصل تلقائياً على هذه الدالة — دون الحاجة لكتابة أي كود داخل كتلة impl:

struct Guest;

impl Greet for Guest {}

let visitor = Guest;
println!("{}", visitor.greet());  // أهلاً بك!

إنّ impl Greet for Guest {} الفارغة صالحة لأن السمة (trait) توفر السلوك بالفعل. تقوم البنية (struct) ببساطة بـ "الموافقة" على السمة وتتلقى الدالة الافتراضية مجانًا.

هذا النمط مفيد عندما تريد تعريف سلوك مشترك يعمل في معظم الحالات. الأنواع التي تحتاج إلى شيء مختلف يمكنها تجاوز السلوك الافتراضي (والذي ستتعلمه لاحقاً)، بينما الأنواع التي تكتفي بالسلوك القياسي لا تحتاج إلى تكرار نفسها.

challenge icon

التحدي

سهل

دعونا نستكشف قوة التنفيذات الافتراضية (default implementations) من خلال بناء نظام تنبيهات! ستقوم بإنشاء سمة (trait) توفر سلوكاً قياسياً جاهزاً، بحيث يمكن للأنواع الاستفادة منه دون كتابة كود متكرر.

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

  • notifiable.rs: قم بتعريف سمة عامة Notifiable مع طريقة notify(&self) -> String تحتوي على تنفيذ افتراضي. يجب أن يعيد التنفيذ الافتراضي "You have a new notification!". أي نوع يقوم بتنفيذ هذه السمة سيحصل تلقائياً على هذا السلوك دون الحاجة لكتابة أي شيء داخل كتلة impl الخاصة به.
  • alerts.rs: قم بإنشاء هيكلين بسيطين (unit structs) عامين ينفذان السمة الخاصة بك:
    • EmailAlert — ينفذ Notifiable بكتلة impl فارغة (يستخدم الافتراضي)
    • SystemAlert — ينفذ أيضاً Notifiable بكتلة impl فارغة (يستخدم الافتراضي)
    سيحصل كلا الهيكلين تلقائياً على رسالة التنبيه الافتراضية دون أن تضطر لكتابة أي محتوى للطرق!
  • main.rs: اجمع وحداتك معاً واستعرض كيف يتشارك كلا نوعي التنبيهات نفس السلوك الافتراضي. قم بإنشاء مثيلات (instances) من كلا الهيكلين واستدعِ طرق notify الخاصة بهما.

في ملفك الرئيسي، قم بإنشاء EmailAlert و SystemAlert، ثم اطبع تنبيهاتهما في أسطر منفصلة.

يجب أن يكون مخرجك:

You have a new notification!
You have a new notification!

لاحظ كيف ينتج كلا النوعين مخرجات متطابقة—هذا هو جمال التنفيذات الافتراضية! لم يحتج أي من الهيكلين لكتابة أي كود لطريقة notify، ومع ذلك يمتلك كلاهما سلوك تنبيه يعمل بكامل طاقته. في الدرس القادم، ستتعلم كيفية تجاوز (override) هذه الافتراضات عندما يحتاج نوع ما إلى سلوك مخصص.

ورقة مرجعية

يمكن أن تمتلك دوال الـ Trait تطبيقات افتراضية عبر توفير جسم للدالة بدلاً من مجرد التوقيع:

trait Greet {
    fn greet(&self) -> String {
        String::from("Hello there!")
    }
}

تتلقى الأنواع التي تطبق الـ trait السلوك الافتراضي تلقائياً دون الحاجة لكتابة أي كود:

struct Guest;

impl Greet for Guest {}

let visitor = Guest;
println!("{}", visitor.greet());  // Hello there!

تعتبر كتلة impl الفارغة صالحة عندما يوفر الـ trait تطبيقات افتراضية. يسمح هذا للأنواع بالانضمام إلى السلوك المشترك دون تكرار.

جرّب بنفسك

mod notifiable;
mod alerts;

use notifiable::Notifiable;
use alerts::{EmailAlert, SystemAlert};

fn main() {
    // TODO: إنشاء مثيل لـ EmailAlert
    
    // TODO: إنشاء مثيل لـ SystemAlert
    
    // TODO: طباعة الإشعار من EmailAlert
    
    // TODO: طباعة الإشعار من SystemAlert
}
quiz iconاختبر نفسك

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

جميع دروس Object Oriented Programming