محتويات الدورة

Rust / المتوسط / الدرس 8

السمات والأنواع العامة والقيود

صف السلوك المشترك بالسمات واكتب دوال عامة تعبّر قيودها عن العمليات المطلوبة فعلًا.

وقت القراءة التقريبي: 4 دقيقةتاريخ مراجعة المحتوى
في هذه الصفحة

أهداف الدرس

  • تطبيق سمة واستدعاؤها عبر قيد عام.
  • تمييز الأنواع المرتبطة من المعاملات العامة.
  • فصل صياغة السمات عن التزامات الدلالة والعمر.

السمة تسمّي واجهة

تعلن السمة سلوكًا توفره الأنواع المطبقة، وقد تضم أساليب لازمة وافتراضية وأنواعًا أو ثوابت مرتبطة. يتيح T: Summary استدعاء أساليبها مع حفظ النوع المحدد وقت الترجمة. اتبع العمليات الفعلية بدل طلب Clone أو Copy أو Debug عادة. قد يخالف تطبيق صحيح صياغيًا توقعات المجال، فوثّق القوانين كاتساق المساواة أو عدم تعديل الملخص. يفحص المترجم التواقيع وقواعد الأنواع لا صدق كل وعد عملي.

تطبيق عملية مجال صغيرة

يطبق البرنامج Summary على Report محلي ويستخدم render عامة. يستعير الأسلوب &self فلا يستهلك التقرير ويعيد String مملوكة مستقلة. يفصل ذلك النموذج عن عرضه. ينبغي أن تعبّر السمة عن قدرة ذات معنى لا مجموعة تسهيلات متناثرة. يستطيع المستدعي إعادة استخدام render مع تطبيقات مختلفة دون تبديل مركزي للأنواع، بشرط احترام معنى الملخص الموثق.

rust دالة عامة تعتمد على قدرة
trait Summary { fn summary(&self) -> String; }
struct Report { open: u32 }
impl Summary for Report {
    fn summary(&self) -> String { format!("open={}", self.open) }
}
fn render<T: Summary>(value: &T) -> String { value.summary() }
fn main() {
    let report = Report { open: 3 };
    println!("{}", render(&report));
}
الناتج المتوقع
open=3

تحتاج render إلى Summary فقط، وتستعير Report وتعيد نصًا منسقًا مستقلًا.

طلب العمليات المستخدمة فقط

تحتاج الدالة الثانية المساواة فقط فتكتفي PartialEq. تبحث في عناصر مستعارة وتعيد فهرسًا مملوكًا فتتجنب اعتماد عمر للمخرج. لا تلزم Clone لأنها لا تكرر العناصر. تتوقف position عند أول تطابق وتعيد None عند غيابه. قد تفصل واجهة أعم نوع العنصر عن الاستعلام، لكن لتخدم حاجة فعلية. وضّح التشخيص بأسماء مساعدة وقيود قريبة من العملية العامة.

rust مساواة دون استنساخ زائد
fn first_equal<T: PartialEq>(values: &[T], target: &T) -> Option<usize> {
    values.iter().position(|value| value == target)
}
fn main() {
    let values = [4, 7, 7];
    println!("{:?} {:?}", first_equal(&values, &7), first_equal(&values, &9));
}
الناتج المتوقع
Some(1) None

أول سبعة في الفهرس واحد ابتداءً من الصفر، وتسعة غائبة وتبقى المدخلات مستعارة.

اختيار تمثيل اختلاف الأنواع

قد يسمح المعامل العام بتطبيقات مختلفة وفق اختياره، ويحدد التطبيق نوعًا مرتبطًا لتلك السمة. تستخدم Iterator النوع Item ليعرف المستهلك ناتج next. تستعمل الاستدعاءات العامة غالبًا تخصيصًا ساكنًا قد يزيد حجم الشيفرة. يتيح dyn Trait أو Box<dyn Trait> اختيارًا وقت التنفيذ إذا كانت السمة متوافقة معه. لا تدعم كل سمة ذلك؛ فأساليب عامة وبعض استعمالات Self تحتاج تصميمًا دقيقًا. لا تكون استراتيجية واحدة أسرع في كل الأحمال.

الحفاظ على اتساق التطبيقات

تمنع قواعد الاتساق تطبيقات السمات المتعارضة. تشترط القواعد عادة سمة محلية أو نوعًا محليًا مناسبًا بدل تطبيقات اعتباطية لسمة ونوع خارجيين. يوفّر غلاف newtype نوعًا محليًا بعقد مضبوط. اشتق السمات فقط إذا وافقت دلالتها النموذج؛ فقد يختلف الترتيب المشتق من التمثيل عن ترتيب العمل. اختبر التطبيقات عبر الواجهة العامة بما فيها الفراغ والمساواة غير المعتادة. لا تلغي القيود مسؤوليات الحساب والتزامن والموارد.

الأخطاء الشائعة وإصلاحها

تعذر استدعاء أسلوب متوقع في دالة عامة.

لماذا يحدث؟
ينقص قيد السمة المطلوبة أو استيرادها.
كيف تصلحه؟
أضف قيد القدرة الأدنى واستورد سمتها.
كيف تتجنب تكراره؟
استنتج القيود من عمليات الجسم.

تعارض تطبيق عام مع آخر.

لماذا يحدث؟
تتداخل مجموعتا الأنواع المسموحتان.
كيف تصلحه؟
ضيّق التصميم أو استخدم غلافًا محليًا.
كيف تتجنب تكراره؟
راجع الاتساق قبل نشر تطبيقات واسعة.

تعذر استخدام سمة بصيغة dyn Trait.

لماذا يحدث؟
واجهتها غير متوافقة مع الاختيار الديناميكي.
كيف تصلحه؟
افصل الأساليب الديناميكية عن القدرات العامة فقط.
كيف تتجنب تكراره؟
اختر حاجة الاختيار قبل تثبيت السمة العامة.

اختبر فهمك

1. هل تحتاج first_equal إلى Clone عندما تكون T هي String؟ اشرح تقديم الاستعلام والملكية بعدها.

اعرض الحل المشروح

لا. مرّر شريحة String مستعارة ومرجعًا إلى String للاستعلام. تقارن PartialEq بمراجع مشتركة وتعيد الدالة فهرسًا فقط. يحتفظ المتجه والاستعلام بالملكية. يمكن تصميم استعلام مختلط String/str أكثر راحة، وهو تحسين منفصل لا مبرر لاستنساخ العناصر.

2. تريد مكتبة سياسة عرض خاصة لنوع من حزمة أخرى. اشرح أسلوب newtype دون تعديل الحزمة الخارجية.

اعرض الحل المشروح

عرّف بنية غلاف محلية تحتوي القيمة الخارجية ثم طبّق سمة العرض أو المجال على الغلاف حيث تسمح القواعد. يحدد الغلاف ملكية محلية وتفسيرًا صريحًا دون فرض سياسة عامة للنوع الخارجي. أظهر الإنشاء والاستعارة عند الحاجة واختبر التنسيق وفق عقد الغلاف.

أهم ما تعلمته

  • تصف السمات قدرات ووعودًا دلالية.
  • استخدم قيودًا دنيا واختيارًا مقصودًا.
  • يشكل الاتساق والملكية الواجهات العامة.

المراجع الرسمية