جملة 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 بسيط.
التحدي
سهللنقم ببناء نظام لمعالجة البيانات يستخدم بند 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.
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 قم باستدعاء
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس 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 مع المعاملاتملخص - مشغل الوسائط