مقدمة: المتجهات بسيطة، إلا عندما تحتاج إلى لصقها
\nتخيل: أنت تكتب برنامجاً بلغة Rust يقوم بمعالجة البيانات. تحصل على اثنين من Vec<i32> وتريد دمجهما في واحد. قد يبدو الأمر بسيطاً؟ لكن كل من طرح هذا السؤال على Stack Overflow (وهناك الآلاف!) يعلم: في Rust هناك 5 طرق على الأقل للقيام بذلك، ونصفها عبارة عن أخطاء إما لن يتم تجميعها، أو ستستهلك كل الأداء.
في هذه المقالة، سنحلل السؤال الشائع «ما هي أفضل طريقة لدمج المتجهات في Rust؟» ونحوله إلى دليل عملي. ستتعلم كيفية دمج المتجهات بشكل صحيح، وما هي المزالق التي تنتظر المبتدئين، وكيفية كتابة كود فعال في Rust. هيا بنا!
\n\nلماذا تعتبر عملية دمج المتجهات في Rust ليست بالمهمة التافهة؟
\nعلى عكس Python أو JavaScript، حيث يمكنك ببساطة كتابة list1 + list2، يتطلب Rust منك تحديد ما تريد فعله بالذاكرة بوضوح. المتجه في Rust ليس مجرد قائمة، بل هو هيكل يمتلك البيانات في الكومة (heap). العمليات عليه قد تؤدي إلى:
- \n
- إعادة تخصيص (نسخ المخزن المؤقت بالكامل). \n
- فقدان الملكية (move semantics). \n
- استنساخ غير ضروري (إذا كانت البيانات كبيرة). \n
لذلك، يعتمد اختيار الطريقة على السياق: هل تحتاج إلى الاحتفاظ بالمتجهات الأصلية، وما هو نوع البيانات بداخلها، وهل السرعة مهمة.
\n\nأهم 5 أخطاء عند دمج المتجهات في Rust
\nدعنا نستعرض أكثر المزالق شيوعاً التي يقع فيها المبتدئون (وليسوا فقط).
\n\nالخطأ رقم 1: استخدام + مع Vec (لن يتم تجميعه)
\nالمحاولة الأكثر بديهية، ولكنها خاطئة:
\nlet v1 = vec![1, 2, 3];\nlet v2 = vec![4, 5, 6];\nlet v3 = v1 + v2; // خطأ! cannot add `Vec<{integer}>` to `Vec<{integer}>`\nعامل التشغيل + محمّل فقط للسلاسل النصية والأرقام، وليس للمتجهات. لا يسمح Rust بجمع المجموعات «بشكل مباشر».
الخطأ رقم 2: نسيان الـ move وفقدان البيانات
\nكثيرون يستخدمون append ويتفاجؤون بأن المتجه الأول أصبح فارغاً:
let mut v1 = vec![1, 2, 3];\nlet mut v2 = vec![4, 5, 6];\nv1.append(&mut v2);\nprintln!("{:?}", v2); // فارغ! v2 أصبح فارغاً الآن.\nappend ينقل العناصر من المتجه الثاني إلى الأول، تاركاً v2 فارغاً. هذا فعال، لكنه ليس متوقعاً دائماً.
الخطأ رقم 3: الاستنساخ الساذج لكل شيء
\nعند الحاجة إلى الاحتفاظ بكلا المتجهين الأصليين، يكتب المبتدئون غالباً:
\nlet v1 = vec![1, 2, 3];\nlet v2 = vec![4, 5, 6];\nlet mut v3 = v1.clone();\nv3.extend(v2.clone()); // استنساخان!\nبالنسبة للمتجهات الكبيرة التي تحتوي على String أو هياكل معقدة، هذا يقتل الأداء. من الأفضل استخدام المراجع (references) أو chain.
الخطأ رقم 4: تجاهل capacity عند استخدام extend
\nاستخدام extend البسيط قد يسبب عمليات إعادة تخصيص متعددة:
let mut v1 = vec![1, 2, 3];\nlet v2 = vec![4, 5, 6];\nv1.extend(v2); // إذا كانت سعة v1 صغيرة، ستحدث إعادة تخصيص.\nإذا كنت تعرف الحجم النهائي، فمن الأفضل تخصيص الذاكرة مسبقاً: v1.reserve(v2.len()).
الخطأ رقم 5: الخلط بين extend و append
\nextend يقبل مكرراً (iterator) ويمكنه استنساخ العناصر (إذا مررت &vec). append ينقل العناصر دون استنساخ. الاختيار غير واضح حتى تقرأ التوثيق.
أفضل طرق دمج المتجهات في Rust (مع أمثلة)
\nالآن بعد أن عرفنا العدو، دعنا نستعرض الطرق الصحيحة. كل منها مناسب لسيناريو معين.
\n\nالطريقة 1: extend — شاملة ومفهومة
\nالطريقة الأكثر شيوعاً. تضيف عناصر