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

الـ Traits مع المعاملات

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

حتى الآن، لم تأخذ طرق السمات (trait methods) الخاصة بنا سوى &self كمعلمة. ولكن يمكن لطرق السمات قبول معلمات إضافية تماماً مثل الطرق العادية—وهذا يجعلها أكثر فائدة بكثير للعمليات الواقعية.

عند تعريف سمة (trait)، يمكنك تضمين أي معلمات تحتاجها في تواقيع الدوال (method signatures):

trait Calculator {
    fn add(&self, a: i32, b: i32) -> i32;
    fn multiply(&self, a: i32, b: i32) -> i32;
}

تتطلب سمة Calculator هذه طريقتين، كل منهما تقبل عددين صحيحين بالإضافة إلى &self. يجب على أي نوع يقوم بتنفيذ هذه السمة توفير كلتا العمليتين بهذه التواقيع المحددة تماماً.

إليك كيف يمكن لـ struct تنفيذ ذلك:

struct BasicCalc;

impl Calculator for BasicCalc {
    fn add(&self, a: i32, b: i32) -> i32 {
        a + b
    }
    
    fn multiply(&self, a: i32, b: i32) -> i32 {
        a * b
    }
}

الآن يمكنك استخدام هذه الطرق مع الوسائط:

let calc = BasicCalc;
println!("{}", calc.add(5, 3));       // 8
println!("{}", calc.multiply(4, 7));  // 28

تحدد السمة (trait) ما هي المعاملات التي تقبلها كل دالة (method)، بينما يحدد التنفيذ (implementation) كيفية استخدام تلك المعاملات. يتيح ذلك للأنواع المختلفة تنفيذ العمليات نفسها بطريقتها الخاصة—فربما يقوم LoggingCalc بطباعة كل عملية قبل إرجاع النتيجة.

challenge icon

التحدي

سهل

لنقم ببناء مجموعة أدوات لمعالجة النصوص حيث يمكن للمعالجات المختلفة تحويل النص بطرقها الخاصة! ستقوم بإنشاء سمة (trait) باسم TextProcessor تحتوي على دوال تقبل معاملات، ثم تقوم بتنفيذها لنوعين مختلفين من المعالجات.

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

  • processor.rs: قم بتعريف سمة عامة TextProcessor مع دالتين تقبلان معاملات:
    • repeat(&self, text: &str, times: u32) -> String — تكرر النص المعطى عدداً محدداً من المرات.
    • truncate(&self, text: &str, max_len: usize) -> String — تقصر النص إلى الحد الأقصى المحدد للطول.
  • processors.rs: قم بإنشاء هيكلين (structs) عامين ينفذان السمة الخاصة بك:
    • SimpleProcessor — هيكل وحدة (unit struct) يكرر النص مع وجود مسافات بين كل تكرار (على سبيل المثال، "Hi" مكررة 3 مرات تصبح "Hi Hi Hi") ويقوم بالقص ببساطة عند الحد الأقصى للطول.
    • FancyProcessor — هيكل وحدة يكرر النص مع وجود " * " بين التكرارات (على سبيل المثال، "Hi" مكررة 3 مرات تصبح "Hi * Hi * Hi") ويقوم بالقص عن طريق إضافة "..." إذا تم تقصير النص (فقط إذا كان النص الأصلي أطول من max_len).
  • main.rs: اجمع وحداتك معاً واعرض كيف تنتج نفس دوال السمة نتائج مختلفة بناءً على المعالج الذي تستخدمه.

في ملفك الرئيسي، قم بإنشاء كلا المعالجين واستخدم المدخلات لاختبارهما. ستتلقى ثلاثة مدخلات: سلسلة نصية، وعدد التكرارات، والحد الأقصى للطول.

اطبع أربعة أسطر توضح سلوك كل معالج:

Simple repeat: {result}
Simple truncate: {result}
Fancy repeat: {result}
Fancy truncate: {result}

على سبيل المثال، مع المدخلات Hello، و 3، و 4:

Simple repeat: Hello Hello Hello
Simple truncate: Hell
Fancy repeat: Hello * Hello * Hello
Fancy truncate: Hell...

لاحظ كيف يفي كلا المعالجين بنفس عقد TextProcessor، ولكن كل منهما يحول النص بطريقته الفريدة. تحدد السمة (trait) ما هي المعاملات التي تقبلها الدوال، بينما يقرر كل تنفيذ كيفية استخدامها!

ستتلقى ثلاثة مدخلات: النص المراد معالجته، وعدد التكرارات (يتم تحليله كـ u32)، والحد الأقصى للطول للقص (يتم تحليله كـ usize).

ورقة مرجعية

يمكن لأساليب السمة (Trait methods) قبول معلمات إضافية تتجاوز &self:

trait Calculator {
    fn add(&self, a: i32, b: i32) -> i32;
    fn multiply(&self, a: i32, b: i32) -> i32;
}

تنفيذ سمة (trait) بمعلمات:

struct BasicCalc;

impl Calculator for BasicCalc {
    fn add(&self, a: i32, b: i32) -> i32 {
        a + b
    }
    
    fn multiply(&self, a: i32, b: i32) -> i32 {
        a * b
    }
}

استخدام أساليب السمة مع الوسائط (arguments):

let calc = BasicCalc;
println!("{}", calc.add(5, 3));       // 8
println!("{}", calc.multiply(4, 7));  // 28

تحدد السمة (trait) ما هي المعلمات التي يقبلها كل أسلوب، بينما يحدد التنفيذ كيفية استخدام تلك المعلمات.

جرّب بنفسك

mod processor;
mod processors;

use processor::TextProcessor;
use processors::{SimpleProcessor, FancyProcessor};

fn main() {
    // قراءة المدخلات
    let mut text = String::new();
    std::io::stdin().read_line(&mut text).expect("Failed to read line");
    let text = text.trim();
    
    let mut times_input = String::new();
    std::io::stdin().read_line(&mut times_input).expect("Failed to read line");
    let times: u32 = times_input.trim().parse().expect("Failed to parse times");
    
    let mut max_len_input = String::new();
    std::io::stdin().read_line(&mut max_len_input).expect("Failed to read line");
    let max_len: usize = max_len_input.trim().parse().expect("Failed to parse max_len");
    
    // إنشاء المعالجات
    let simple = SimpleProcessor;
    let fancy = FancyProcessor;
    
    // TODO: استخدم المعالجات لتحويل النص وطباعة النتائج
    // طباعة أربعة أسطر:
    // Simple repeat: {result}
    // Simple truncate: {result}
    // Fancy repeat: {result}
    // Fancy truncate: {result}
}
quiz iconاختبر نفسك

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

جميع دروس Object Oriented Programming