«كيف تطبع Vec؟» — سؤال طرحه كل مطور Rust
\n\nإذا كنت قد كتبت أي وقت مضى بلغة Rust وحاولت ببساطة طباعة متجه على الشاشة، فمن المؤكد أنك واجهت هذا:
\n\nfn 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 — يطلب منك المترجم تحديد كيف تريد عرض المجموعة بالضبط. وهذا رائع، لأنه يمنحك تحكمًا كاملاً.
في هذه المقالة، سنستعرض جميع الطرق الأساسية لطباعة Vec في Rust: من الطباعة السريعة للتصحيح إلى إنشاء تنسيق جميل للمستخدم. ستتعرف على أي طريقة تستخدمها ومتى، وستتوقف عن الخوف من أخطاء الترجمة.
\n\nلماذا لا تطبق Vec واجهة Display؟
\n\nقبل أن نغوص في الكود، دعنا نفهم فلسفة Rust. واجهة Display مخصصة لعرض البيانات للمستخدم — بالطريقة التي تريد رؤيتها في الواجهة. أما Debug — فهي للتصحيح والسجلات.
بالنسبة للمتجه، من المستحيل تخمين التنسيق الذي تحتاجه:
\n- \n
- عرض العناصر مفصولة بفاصلة؟ \n
- كل عنصر في سطر جديد؟ \n
- بين قوسين مربعين، كمصفوفة؟ \n
- أو على شكل جدول؟ \n
لذلك، قرر مطورو Rust عدم فرض تنسيق واحد، بل ترك الخيار للمبرمج. دعنا نرى الخيارات المتاحة لدينا.
\n\nالطريقة 1: الطباعة السريعة للتصحيح (Debug)
\n\nأبسط طريقة هي استخدام {:?} أو {:#?} (طباعة جميلة). لهذا، يجب أن يطبق نوع عناصر المتجه واجهة Debug.
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)]:
#[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\nfn 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 (متاحة للشرائح):
fn main() {\n let words = vec!["hello", "world", "rust"];\n let joined = words.join(", ");\n println!("{}", joined); //