iter مقابل into_iter: معركة عمالقة التكرار في Rust
\n\nإذا سبق لك أن كتبت حلقة على متجه في Rust، فبالتأكيد صادفت ثلاثة توائم: iter()، into_iter() و iter_mut(). للوهلة الأولى، كلهم يفعلون نفس الشيء - يسمحون لك بالمرور عبر العناصر. لكن الفرق بينهم أعمق مما يبدو، ويكمن في قلب Rust - نظام الملكية.
تخيل أنك باريستا، ومجموعتك هي حبوب البن. iter() يسمح لك بالنظر إلى الحبوب، وشمها، ولكن لا تلمسها. into_iter() هو عندما تأخذ الحبوب، تطحنها وتصنع إسبريسو، وبعد ذلك تختفي الحبوب. أما iter_mut() - فيمكنك ليس فقط النظر، بل أيضًا طحن الحبوب مباشرة في الكيس، وتغيير شكلها.
اليوم سنشرح iter مقابل into_iter كما يتم شرحه في Stack Overflow، ولكن مع أمثلة حية وغوص عميق تحت الغطاء. هيا بنا!
\n\nما هو المكرر في Rust؟
\n\nالمكرر هو كائن يعرف كيفية الحصول على العناصر من المجموعة بشكل تسلسلي. في Rust، المكررات كسولة: لا تفعل شيئًا حتى تستدعي next(). لكن الأهم - كل طريقة تكرار تتعامل مع ملكية البيانات بشكل مختلف.
إليك الطرق الثلاث الرئيسية:
\n- \n
iter()- يقترض العناصر (لا يأخذ الملكية) \n into_iter()- يستهلك المجموعة (يأخذ الملكية) \n iter_mut()- يقترض مع إمكانية التعديل \n
لننظر إلى الكود. لنفترض أن لدينا متجهًا للأسماء:
\n\nlet names = vec!["آنا".to_string(), "بوريس".to_string(), "فيكتور".to_string()];\n\nمثال 1: iter() - فقط للنظر
\n\nfn main() {\n let names = vec!["آنا".to_string(), "بوريس".to_string(), "فيكتور".to_string()];\n \n // iter() يعيد &String (مرجع)\n for name in names.iter() {\n println!("مرحبًا، {}!", name);\n }\n \n // names لا يزال متاحًا!\n println!("المتجه حي: {:?}", names);\n}\n\nلاحظ: بعد الحلقة، نستخدم names بسهولة. لماذا؟ لأن iter() أعاد مرجعًا لكل عنصر. بقيت الملكية للمتجه. هذا آمن ويمكن التنبؤ به.
مثال 2: into_iter() - احرق الجسور
\n\nfn main() {\n let names = vec!["آنا".to_string(), "بوريس".to_string(), "فيكتور".to_string()];\n \n // into_iter() يعيد String (الملكية تنتقل)\n for name in names.into_iter() {\n println!("وداعًا، {}!", name);\n }\n \n // خطأ! names لم يعد موجودًا\n // println!("المتجه حي: {:?}", names); // ❌ borrow of moved value\n}\n\nها هو الفرق الرئيسي. into_iter() يستهلك المجموعة. كل عنصر ينتقل إلى الحلقة، ويصبح المتجه الأصلي غير صالح. إذا كنت بحاجة للحفاظ على المجموعة للاستخدام لاحقًا - into_iter() ليس خيارك.
مثال 3: iter_mut() - التعديل دون تدمير
\n\nfn main() {\n let mut names = vec!["آنا".to_string(), "بوريس".to_string(), "فيكتور".to_string()];\n \n // iter_mut() يعيد &mut String (مرجع قابل للتعديل)\n for name in names.iter_mut() {\n name.push_str(" (ضيف)");\n }\n \n println!("المتجه المعدل: {:?}", names);\n // الإخراج: ["آنا (ضيف)", "بوريس (ضيف)", "فيكتور (ضيف)"]\n}\n\nهنا نغير العناصر في مكانها، لكننا لا نأخذ الملكية. مثالي للتحويلات.
\n\nتحت الغطاء: ماذا يعيد كل طريقة؟
\n\nلفهم iter مقابل into_iter حقًا، لننظر إلى المكتبة القياسية. بالنسبة للمتجه Vec<T>:
- \n
iter()يعيدstd::slice::Iter<T>- ينفذIterator<Item = &T>