طباعة Vec في Rust: من المبتدئ إلى المحترف

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

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

ابدأ الدورة

«كيف تطبع Vec؟» — سؤال طرحه كل مطور Rust

\n\n

إذا كنت قد كتبت أي وقت مضى بلغة Rust وحاولت ببساطة طباعة متجه على الشاشة، فمن المؤكد أنك واجهت هذا:

\n\n
fn main() {\n    let numbers = vec![1, 2, 3, 4, 5];\n    println!("{}", numbers); // خطأ!\n}
\n\n

يستقبلك المترجم برسالة حمراء: `Vec<{integer}>` doesn't implement `std::fmt::Display`. مألوف؟ هذا السؤال على Stack Overflow حصد آلاف المشاهدات، وليس من دون سبب. لا يوجد «سحر» في Rust — يطلب منك المترجم تحديد كيف تريد عرض المجموعة بالضبط. وهذا رائع، لأنه يمنحك تحكمًا كاملاً.

\n\n

في هذه المقالة، سنستعرض جميع الطرق الأساسية لطباعة Vec في Rust: من الطباعة السريعة للتصحيح إلى إنشاء تنسيق جميل للمستخدم. ستتعرف على أي طريقة تستخدمها ومتى، وستتوقف عن الخوف من أخطاء الترجمة.

\n\n

لماذا لا تطبق Vec واجهة Display؟

\n\n

قبل أن نغوص في الكود، دعنا نفهم فلسفة Rust. واجهة Display مخصصة لعرض البيانات للمستخدم — بالطريقة التي تريد رؤيتها في الواجهة. أما Debug — فهي للتصحيح والسجلات.

\n\n

بالنسبة للمتجه، من المستحيل تخمين التنسيق الذي تحتاجه:

\n
    \n
  • عرض العناصر مفصولة بفاصلة؟
  • \n
  • كل عنصر في سطر جديد؟
  • \n
  • بين قوسين مربعين، كمصفوفة؟
  • \n
  • أو على شكل جدول؟
  • \n
\n\n

لذلك، قرر مطورو Rust عدم فرض تنسيق واحد، بل ترك الخيار للمبرمج. دعنا نرى الخيارات المتاحة لدينا.

\n\n

الطريقة 1: الطباعة السريعة للتصحيح (Debug)

\n\n

أبسط طريقة هي استخدام {:?} أو {:#?} (طباعة جميلة). لهذا، يجب أن يطبق نوع عناصر المتجه واجهة Debug.

\n\n
fn main() {\n    let numbers = vec![1, 2, 3, 4, 5];\n    println!("{:?}", numbers);    // [1, 2, 3, 4, 5]\n    println!("{:#?}", numbers);   // طباعة جميلة:\n                                  // [\n                                  //     1,\n                                  //     2,\n                                  //     3,\n                                  //     4,\n                                  //     5\n                                  // ]\n}
\n\n

متى تستخدم: التصحيح، التسجيل، الفحص السريع. عادةً لا تصلح للإنتاج — التنسيق غير مرن.

\n\n

مهم: إذا كان النوع الخاص بك لا يطبق Debug، سينبهك المترجم. لهياكل البيانات الخاصة بك، يمكنك إضافة #[derive(Debug)]:

\n\n
#[derive(Debug)]\nstruct Point {\n    x: f64,\n    y: f64,\n}\n\nfn main() {\n    let points = vec![Point { x: 1.0, y: 2.0 }, Point { x: 3.0, y: 4.0 }];\n    println!("{:?}", points);\n}
\n\n

الطريقة 2: التكرار اليدوي باستخدام المكرر

\n\n

الطريقة الأكثر مرونة — كتابة حلقة خاصة بك. تحصل على تحكم كامل في التنسيق.

\n\n
fn main() {\n    let words = vec!["hello", "world", "rust"];\n    \n    // الخيار 1: مفصولة بفاصلة\n    for (i, word) in words.iter().enumerate() {\n        if i > 0 {\n            print!(", ");\n        }\n        print!("{}", word);\n    }\n    println!(); // hello, world, rust\n\n    // الخيار 2: كل عنصر في سطر جديد\n    for word in &words {\n        println!("- {}", word);\n    }\n    // - hello\n    // - world\n    // - rust\n}
\n\n

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

\n\n

الطريقة 3: استخدام المكرر مع collect و join

\n\n

إذا كنت تحتاج فقط إلى ربط العناصر في سلسلة نصية، يمكنك استخدام join من واجهة SliceConcatExt (متاحة للشرائح):

\n\n
fn main() {\n    let words = vec!["hello", "world", "rust"];\n    let joined = words.join(", ");\n    println!("{}", joined); //                

المدونات

توصيات الكتب