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

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

المكررات والإغلاقات والملكية

ركّب تكرارًا كسولًا بملكية واضحة واختر التقاط الإغلاقات بوعي واجمع النتائج عند الحاجة إلى ملكية.

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

أهداف الدرس

  • تمييز iter وiter_mut وinto_iter للمجموعات المملوكة.
  • شرح المحولات الكسولة والمستهلكات النهائية وcollect.
  • ربط أسلوب الالتقاط بسلوك Fn وFnMut وFnOnce.

معرفة ما تنتجه كل خطوة

تملك Iterator نوع Item مرتبطًا وnext تعيد Option<Item>. مع Vec<T> مملوكة تستعير iter العناصر مشتركًا وiter_mut للتعديل وتستهلك into_iter المتجه لتنتج قيمًا مملوكة. قد يختار الاسم نفسه على مرجع تطبيقًا مختلفًا، فافحص المستقبل. تستخدم for السمة IntoIterator وقد تخفي الاختيار. تفيد copied لعناصر Copy وتنادي cloned استنساخ النوع؛ فلا تضفهما لإسكات خطأ غير مفهوم.

المحولات تصف العمل حتى الاستهلاك

تعيد map وfilter مكررات وتنفذان العمل عادة عندما يطلب المستهلك القيم. تستهلك collect الخط وتبني مجموعة محددة. يستعير المثال الأعداد وينسخ الصحيحة الصغيرة ويحتفظ بالزوجية ويضربها بثلاثة ويجمع متجهًا مملوكًا. يبقى الأصل صالحًا لأن iter لم تنقله. يستقبل شرط filter مرجعًا إلى العنصر المرشح حتى بعد copied؛ وقد تتعامل العمليات معه دون فك صريح. راجع Item في كل مرحلة عند تعقد السلسلة.

rust وصف كسول يُجمع في قيم مملوكة
fn main() {
    let numbers = vec![1u32, 2, 3, 4];
    let results: Vec<u32> = numbers.iter().copied()
        .filter(|value| value % 2 == 0)
        .map(|value| value * 3)
        .collect();
    println!("{:?} {}", results, numbers.len());
}
الناتج المتوقع
[6, 12] 4

يصير اثنان وأربعة ستة واثني عشر، ويتبع ترتيب الجمع المصدر ويبقى الأصل أربعة عناصر.

أسلوب الالتقاط وسلوك الاستدعاء مختلفان

يلتقط الإغلاق حاجته بالاستعارة أو الملكية وفق الاستخدام والمعدلات. تفرض move الالتقاط بالقيمة وقد تنقل String، لكنها لا تعني استدعاءً واحدًا حتمًا. تتيح FnOnce استهلاك الحالة وFnMut تعديلها وFn الوصول المشترك، وقد يطبق الإغلاق عدة سمات. يملك المثال البادئة ويستعيرها أثناء تنسيق كل نتيجة، فيُستدعى مرارًا دون استنساخها لكل مرة.

rust إغلاق مالك قابل لإعادة الاستخدام
fn main() {
    let prefix = String::from("item");
    let label = move |id: u32| format!("{prefix}-{id}");
    println!("{} {}", label(3), label(4));
}
الناتج المتوقع
item-3 item-4

تملك label البادئة، وينسق كل استدعاء بوصول مشترك ويعيد String جديدة.

عدم إخفاء السياسة في آثار التكرار

قد تتوقف find وany وposition قبل زيارة الجميع. لذلك قد ينفذ تسجيل أو تعديل داخل map آثارًا أقل من المتوقع. فضّل حلقة صريحة إذا كانت الآثار المرتبة أو الأخطاء المبكرة أو الحالة المشتركة أساس العمل. تعبّر try_fold أو مجموعة Results عن اجتياز قابل للفشل، مع فحص عقد التجميع والتوقف. لا تعد بعدد استدعاءات دقيق إلا بضمان العمليات. وتحتاج التحويلات العددية سياسة حساب مقصودة للمدخلات الخارجية.

الإغلاقات المخزنة تحتفظ بالتزامات العمر

لا يستطيع إغلاق يستعير محليًا تجاوز عمره بأمان. أعد إغلاقًا مالكًا بالتقاطات مناسبة للتنفيذ اللاحق أو أبقِ المستهلك داخل النطاق. ينقل التقاط مرجع بالقيمة المرجع فقط لا كائنه. تضيف المهام المرسلة لخيط Send وقيود static غالبًا. اختر أسلوب التكرار مع مراعاة الوضوح والتكرار والتخصيص والملكية. تفيد السلسلة المختصرة عندما توضح التحويل، وتناسب الحلقة عندما توضح العقد أكثر.

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

خط معالجة لا ينفذ عملًا ظاهرًا.

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

المتجه الأصلي غير متاح بعد التكرار.

لماذا يحدث؟
استهلكته into_iter على القيمة المملوكة.
كيف تصلحه؟
استخدم iter للمراقبة المشتركة.
كيف تتجنب تكراره؟
تتبّع نوع المستقبل وItem.

إغلاق معاد يستعير محليًا ميتًا.

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

اختبر فهمك

1. غيّر الخط ليحتفظ بالفردية ويزيدها واحدًا. أعط المتجه الناتج وهل يُستهلك numbers.

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

تصبح واحد وثلاثة اثنين وأربعة، فتكون results هي [2, 4]. يبقى numbers بأربعة عناصر لأن iter تستعير وcopied تنسخ الأعداد. أما into_iter على المتجه المملوك فتنقل عناصره وتمنع استعمال ارتباطه لاحقًا.

2. يعيد إغلاق move سلسلته الملتقطة مباشرة بدل تنسيقها. هل تبقى الاستدعاءات المتكررة صالحة؟

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

تنقل إعادة String الملتقطة ملكيتها خارج الإغلاق فيُستهلك مرة عبر FnOnce. لا يستطيع استدعاء ثانٍ تملك السلسلة نفسها مجددًا. أعد استعارة بواجهة وعمر مناسبين أو نسخة صريحة إذا كان المقصود نتائج مملوكة متكررة مستقلة.

أهم ما تعلمته

  • افحص Item والملكية في كل مرحلة.
  • تحتاج الأوصاف الكسولة مستهلكًا.
  • لا يعني التقاط move وحده استدعاءً واحدًا.

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