كيفية تحويل Vec<char> إلى سلسلة نصية في Rust: دليل شامل

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: لماذا هذا الموضوع شائع جدًا؟

\n\n

إذا كنت قد كتبت بلغة Rust من قبل، فمن المحتمل أنك واجهت موقفًا لديك فيه Vec<char> وتحتاج إلى الحصول على سلسلة نصية عادية String منه. على Stack Overflow، حصد هذا السؤال آلاف المشاهدات وعشرات الإجابات - وهذا ليس من قبيل الصدفة.

\n\n

في Rust، التعامل مع السلاسل النصية هو فن بحد ذاته. على عكس العديد من اللغات حيث السلاسل النصية هي مجرد مصفوفات من الأحرف، هنا لدينا String (سلسلة قابلة للتغيير ومالكة) و &str (مرجع لشريحة سلسلة). أما Vec<char> فهو متجه من أحرف Unicode ذات أربعة بايتات. لذلك، لا يمكن ببساطة "جمعها" كما في Python أو JavaScript.

\n\n

في هذه المقالة، سنستعرض 4 طرق عملية لتحويل Vec<char> إلى String، وسنناقش الأداء والأخطاء النموذجية للمبتدئين وسنقدم أمثلة جاهزة للكود. هيا بنا!

\n\n

1. الطريقة الأسهل: iter().collect()

\n\n

هذه الطريقة هي كلاسيكية في Rust. إذا كنت معتادًا على التكرارات، فأنت تعلم أن collect() يمكنه جمع أي مجموعة تقريبًا. بالنسبة للسلسلة النصية، يبدو الأمر كالتالي:

\n\n
fn main() {\n    let chars: Vec<char> = vec!['م', 'ر', 'ح', 'ب', 'ا']; // مثال بالعربية\n    let s: String = chars.iter().collect();\n    println!("{}", s); // ستطبع: مرحبا\n}
\n\n

هنا، iter() يُرجع مكررًا على مراجع الأحرف (&char)، و collect() يجمعها في String. يقوم مترجم Rust تلقائيًا بفهم أنه يحتاج إلى تنفيذ trait FromIterator لـ String.

\n\n

هام: إذا كتبت chars.into_iter().collect()، فستحصل على نفس النتيجة، لكن المتجه سيتم استهلاكه (consumed). اختر الخيار بناءً على ما إذا كنت بحاجة إلى المتجه الأصلي لاحقًا أم لا.

\n\n

الإيجابيات والسلبيات

\n
    \n
  • ✅ أقل كود، قابل للقراءة
  • \n
  • ✅ يعمل مع أي مكرر أحرف
  • \n
  • ❌ أبطأ قليلاً من الطرق المتخصصة (لكن في 99% من الحالات، الفرق غير ملحوظ)
  • \n
\n\n

2. التجميع عبر String::from_iter()

\n\n

هذه الطريقة هي في الأساس نفس collect()، لكن بشكل صريح. أحيانًا يكون هذا أكثر ملاءمة للقراءة:

\n\n
use std::iter::FromIterator;\n\nfn main() {\n    let chars: Vec<char> = vec!['R', 'u', 's', 't'];\n    let s = String::from_iter(chars);\n    println!("{}", s); // Rust\n}
\n\n

لاحظ: لقد مررت chars مباشرة، وليس chars.iter(). هذا يعمل لأن Vec<char> ينفذ IntoIterator. إذا كنت بحاجة إلى إبقاء المتجه دون تغيير، استخدم String::from_iter(chars.iter()).

\n\n

شخصيًا، أفضل هذا الخيار عندما يقرأ الكود مبتدئون - اسم الدالة الصريح from_iter يوضح فورًا ما يحدث.

\n\n

3. التكرار اليدوي مع push()

\n\n

أحيانًا تحتاج إلى تحكم أكبر. على سبيل المثال، تريد إضافة بادئة أو تصفية جزء من الأحرف. في هذه الحالة، يمكنك القيام بذلك:

\n\n
fn main() {\n    let chars: Vec<char> = vec!['H', 'e', 'l', 'l', 'o'];\n    let mut s = String::with_capacity(chars.len());\n    \n    for c in chars {\n        s.push(c);\n    }\n    \n    println!("{}", s); // Hello\n}
\n\n

لقد استخدمت String::with_capacity() لتخصيص الذاكرة مسبقًا - وهذا يسرع العملية، حيث لن يكون هناك إعادة تخصيص زائدة عند استخدام push().

\n\n

متى تحتاج هذا؟

\n
    \n
  • عندما تقوم في نفس الوقت بعمليات معالجة أخرى على السلسلة النصية
  • \n
  • عندما تريد إضافة فواصل أو تغيير حالة الأحرف أثناء التنفيذ
  • \n
  • للتعلم - لفهم كيفية عمل السلاسل النصية "تحت الغطاء"
  • \n
\n\n

أداء هذه الطريقة مطابق تقريبًا لـ collect()، إذا قمت

المدونات

توصيات الكتب