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

جملة Where

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

مع إضافة المزيد من قيود السمات (trait bounds)، يمكن أن تصبح تواقيع الدوال صعبة القراءة. فكر في دالة تحتوي على معلمات عامة (generic parameters) متعددة، يتطلب كل منها سمات (traits) عديدة:

fn complex_operation<T: Display + Clone, U: Debug + Summary>(first: T, second: U) {
    // ...
}

هذا يعمل، ولكن التوقيع أصبح مزدحماً. يوفر بند where بديلاً أكثر تنظيماً من خلال نقل قيود السمات (trait bounds) إلى ما بعد قائمة المعاملات:

fn complex_operation<T, U>(first: T, second: U)
where
    T: Display + Clone,
    U: Debug + Summary,
{
    // ...
}

كلا الإصدارين متطابقان وظيفياً—جملة where تتعلق تماماً بسهولة القراءة. تظهر متطلبات كل نوع في سطر خاص بها، مما يسهل فحص ما يحتاجه كل معامل عام (generic parameter).

تصبح جملة where ذات قيمة خاصة عندما تكون القيود معقدة أو عندما يكون لديك العديد من المعلمات العامة. فهي تحافظ على اسم الدالة ومعلماتها مرئية بلمحة سريعة، مع إدراج القيود بشكل منفصل أدناه. هذا هو الأسلوب المفضل في معظم قواعد برمجية Rust عندما تتجاوز القيود مجرد T: Trait بسيط.

challenge icon

التحدي

سهل

لنقم ببناء نظام لمعالجة البيانات يستخدم بند where للحفاظ على وضوح قيود السمات (trait bounds) المعقدة! ستقوم بإنشاء دالة عامة (generic function) بمعاملات أنواع متعددة، يتطلب كل منها سمات مختلفة، وتنظيم القيود بشكل نظيف باستخدام صيغة where.

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

  • processor.rs: قم بتعريف سمتين عامتين (public traits) ودالة عامة تستخدمهما معاً:
    • Summarize — سمة تحتوي على تابع summary يأخذ &self ويعيد String.
    • Validate — سمة تحتوي على تابع validate يأخذ &self ويعيد bool.
    ثم قم بإنشاء دالة عامة عامة تسمى process_items تقبل معاملين من أنواع عامة مختلفة. استخدم بند where لتحديد أن النوع الأول يجب أن يطبق كلاً من Clone و Summarize، بينما يجب أن يطبق النوع الثاني Validate. يجب أن تقوم الدالة بطباعة ملخص العنصر الأول، ثم طباعة ما إذا كان العنصر الثاني صالحاً.
  • main.rs: قم بإنشاء هيكلين عامين (public structs) يطبقان السمات المطلوبة:
    • Article — مع حقل عام title من نوع (String). قم بتطبيق Summarize ليعيد "Article: {}" مع العنوان، وقم باشتقاق Clone.
    • Form — مع حقل عام filled من نوع (bool). قم بتطبيق Validate ليعيد قيمة filled.
    استخدم المدخلات المقدمة لإنشاء Article و Form، ثم استدعِ process_items مع كليهما.

يجعل بند where توقيع الدالة الخاص بك أكثر نظافة بكثير من حشر جميع القيود داخل الأقواس الزاوية. تظهر متطلبات كل نوع في سطر خاص بها، مما يسهل رؤية ما يحتاجه كل معامل عام.

يجب أن يظهر مخرجك الملخص متبوعاً بنتيجة التحقق:

Article: {title}
Valid: {true/false}

على سبيل المثال، مع المدخلات Rust Tips و true:

Article: Rust Tips
Valid: true

ومع المدخلات Breaking News و false:

Article: Breaking News
Valid: false

ستتلقى مدخلين: عنوان المقال وما إذا كان النموذج مكتملاً (يتم تحليله كـ bool).

ورقة مرجعية

يوفر بند where طريقة أنظف لتحديد قيود السمات (trait bounds) للدوال العامة من خلال نقل القيود إلى ما بعد قائمة المعلمات:

fn complex_operation<T, U>(first: T, second: U)
where
    T: Display + Clone,
    U: Debug + Summary,
{
    // ...
}

هذا مطابق وظيفياً لقيود السمات المضمنة (inline trait bounds) ولكنه يحسن من قابلية القراءة:

fn complex_operation<T: Display + Clone, U: Debug + Summary>(first: T, second: U) {
    // ...
}

يكون بند where مفيداً بشكل خاص عندما:

  • لديك معلمات عامة متعددة
  • يتطلب كل معلمة عدة قيود سمات
  • تريد الحفاظ على توقيع الدالة نظيفاً وسهل المسح البصري

تظهر متطلبات كل نوع في سطر خاص بها، مما يسهل رؤية ما يحتاجه كل معلمة عامة. هذا هو الأسلوب المفضل في معظم قواعد برمجية Rust عندما تتجاوز القيود مجرد T: Trait بسيط.

جرّب بنفسك

mod processor;

use processor::{Summarize, Validate, process_items};
use std::io;

// TODO: (String) مع حقل عنوان عام Article قم بتعريف هيكل عام باسم
// Article لـ Clone اشتقاق

// TODO: Article لـ Summarize قم بتنفيذ
// "Article: {title}" يجب أن تعيد طريقة الملخص

// TODO: (bool) مع حقل تعبئة عام Form قم بتعريف هيكل عام باسم

// TODO: Form لـ Validate قم بتنفيذ
// filled يجب أن تعيد طريقة التحقق قيمة

fn main() {
    let mut title = String::new();
    io::stdin().read_line(&mut title).expect("Failed to read line");
    let title = title.trim().to_string();

    let mut filled_input = String::new();
    io::stdin().read_line(&mut filled_input).expect("Failed to read line");
    let filled: bool = filled_input.trim().parse().expect("Failed to parse bool");

    // TODO: بالعنوان المعطى Article قم بإنشاء
    
    // TODO: بالقيمة المعطاة Form قم بإنشاء
    
    // TODO: والنموذج (article) مع المقال process_items قم باستدعاء
}
quiz iconاختبر نفسك

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

جميع دروس Object Oriented Programming